OpenEntityManagerInViewFilter Problems

I looked at this site among others for answers on how OpenEntityManagerInViewFilter works. I have a standard User object that references a role object with a many-many relationship as a set. When I try to change my user from the controller, I get a terrible lazy init exception. For the most part, it seems like this should be very trivial to implement, just adding this to your web.xml:

<filter> <filter-name>oemInViewFilter</filter-name> <filter-class> org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter </filter-class> </filter> <filter-mapping> <filter-name>oemInViewFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 

Now to the things that I tried without success (these are various offers from all over the Internet)

  • Move the above ad to the very top of web.xml
  • @Transactional slap around my controller method and / or the whole class
  • Obviously, that switches the sample type to work with impatience, but it strikes my intentions here.
  • Playing with where I defined my entityManagerFacorty
  • Checked that OpenEntityManager is present in lazy initialization exception, so it gets fired

The only thing I read that it makes sense to me why this does not work is that I load two different sessions due to how my persistence level is configured and the filter captures the wrong one.

Here is this method in my controller where I find the user from the database and throws a lazy initialization exception because it did not extract the role from the user object.

 @RequestMapping(value = "/edit/{id}", method = RequestMethod.GET) public String edit(@PathVariable final Integer id, final ModelMap modelMap) { final User user = userDao.find(id); ******This causes the lazy init exception if (user != null) { modelMap.addAttribute("userInstance", user); modelMap.addAttribute("validRoles", new HashSet<Role>(roleDao.findAll())); return "/user/edit"; } return "redirect:/user/list"; } 

Here is my relevant setup:

web.xml:

 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/board-servlet.xml *****This file references the file with entityManager declared***** /WEB-INF/board-security.xml </param-value> </context-param> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>board</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>board</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.png</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.gif</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.ico</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <filter> <filter-name>oemInViewFilter</filter-name> <filter-class> org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter </filter-class> </filter> <filter-mapping> <filter-name>oemInViewFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>sitemesh</filter-name> <filter-class> com.opensymphony.module.sitemesh.filter.PageFilter </filter-class> </filter> <filter-mapping> <filter-name>sitemesh</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> 

servlet.xml boards

 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> ****This is what pulls in my entityManager <import resource="classpath:persistence-spring-beans.xml"/> <mvc:annotation-driven/> <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="100000"/> </bean> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:message"/> <property name="defaultEncoding" value="UTF-8"/> </bean> </beans> 

persistence- spring - beans.xml

 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <context:annotation-config/> <context:component-scan base-package="com.something" use-default-filters="true"/> <aop:aspectj-autoproxy proxy-target-class="true"/> <tx:annotation-driven transaction-manager="transactionManager"/> <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory"> <property name="persistenceUnitName" value="prodPersistenceUnit"/> <property name="dataSource" ref="c3p0PostgresDataSource"/> <property name="packagesToScan" value="com.something.persistence.dto"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> </bean> <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <bean id="c3p0PostgresDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="org.postgresql.Driver"/> <property name="jdbcUrl" value="jdbc:postgresql://localhost:5432/yellow_hammer"/> <property name="user" value="yellow"/> <property name="password" value="hammer"/> <property name="initialPoolSize" value="3"/> <property name="minPoolSize" value="3"/> <property name="maxPoolSize" value="50"/> <property name="idleConnectionTestPeriod" value="200"/> <property name="acquireIncrement" value="1"/> <property name="maxStatements" value="0"/> <!-- 0 means: statement caching is turned off. --> <property name="numHelperThreads" value="3"/> <!-- 3 is default --> </bean> </beans> 

Let me know if this is not enough for the relevant information.

EDIT UserDao - this extends GenericDao, I will publish it a little lower.

 @Dao public class UserDao extends GenericDao<User> { public User findByUsernameAndPassword(final String username, final String password) { final Query query = entityManager.createQuery("from User user " + "where user.username = :user " + "and user.password = :pass ") .setParameter("user", username) .setParameter("pass", password); return uniqueResult(query); } public List<User> findByRole(final Role roleIn) { if (roleIn == null) { return null; } final Query query = entityManager.createQuery("select user from User user, Role role where role = :roleParam "). setParameter("roleParam", roleIn); return query.getResultList(); } } 

GenericDao

 public class GenericDao<T extends BaseDto> { protected Class<T> entityClass; @PersistenceContext protected EntityManager entityManager; public GenericDao() { final ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass(); this.entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0]; } public T find(final Integer id) { return entityManager.find(entityClass, id); } public List<T> findAll() { final Query query = entityManager.createQuery("from " + entityClass.getSimpleName()); return query.getResultList(); } public T save(final T t) { if (t != null) { return t.getId() != null && t.getVersion() != null ? update(t) : create(t); } return null; } private T create(final T t) { entityManager.persist(t); return t; } private T update(final T t) { return entityManager.merge(t); } public void delete(T t) { t = entityManager.merge(t); entityManager.remove(t); } protected T uniqueResult(final Query query) { final List results = query.getResultList(); if (results.isEmpty()) { return null; } else if (results.size() == 1) { return entityClass.cast(results.get(0)); } // TODO send notification, multiple results found return null; } } 
+3
spring spring-mvc hibernate
source share
3 answers

But now!!

Let me make an assumption: your application name: board?

Correctly? then go ahead and read the rest of the answer!

Yes, you have two entity managers and even two identical application contexts (one application context and one web context). So you have every bean twice!

What happened: you have only one (corresponding) spring configuration file: 'board-servlet.xml' ('persistence-spring - beans.xml' is included in this file, so at least this is one large logical file)

And you create a context from this file twice in "web.xml":

first:

 <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/board-servlet.xml *****This file references the file with entityManager declared***** /WEB-INF/board-security.xml </param-value> </context-param> ... <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 

ContextLoaderListener loads the application context specified in the files in the contextConfigLocation parameter.

second:

 <servlet> <servlet-name>board</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> 

The dispatch servlet creates the web application context in which the XML file resides:

  • named by init-param parameter 'contextConfigLocation'
  • or, if there is no such parameter, it searches for a file named '/WEB-INF/-servlet.xml'

(For more information, see Java Doc FrameworkServlet )

In your case, there is no explicit file specified, so it reads "board-servlet.xml" again.

What you need to do is separate them:

  • remove <import resource="classpath:persistence-spring-beans.xml"/> from board-servlet.xml
  • change contextConfigLocation to web.xml so that it refers to classpath:persistence-spring-beans.xml and /WEB-INF/board-security.xml directcly
  • (not 100% necessary) separate "context: component-scan" so that component scanning in board-servlet.xml checked only on @Controller and component scanning in persistence-spring-beans.xml for others ( @Service , @Component , @Repository and @Dao )
  • Last step: please tell me that it works now.
+11
source share

Even if I cannot answer your question, I can give you some advice.

First, there are some statements that you wrote in your question:

1) Move the above ad to the very top of web.xml

2) Slap @Transactional around my controller method and / or the whole class

1) The order in which filters are applied is determined by the order of filters in web.xml. Therefore, it is correct that OpenEntityManagerInViewFilter must be run before any other filter that uses entities. But in most cases there are not many filters that relay to Entities. (my security filter, if you have expanded it) - But I donโ€™t know if filters should be placed correctly after the servlet declaration

2) If the Layz initialization exception is selected in the JSP, then it is incorrectly incorrect, because it cannot affect the JSP


But what scared me a bit (except that you have a web.xml file that makes it not very easy to read) is a sitemash filter. My first guess is that a sitemash problem is causing the problem. If itโ€™s not difficult, remove the sitemash filter for test purposes only. If the problem goes away, then you have identified the calling component. Strike>

0
source share

You DAO look normal, only the "@Dao" annotation is a bit surprising. In the normal case, one could use "@Repository" - this is a special form of "@Component", but (and this is not very well documented) adds some special functions.

One of these special functions is to throw exceptions, and when I remember, there was another function that improves the annotated bz @PersistenceContext Entity Manager with some additional function that somehow handles the threads and assigns the right thread manager to the correct object manager.

Therefore, I would recommend replacing @Dao with @Repository .

0
source share