1 Attachment(s)
Spring DM + OpenEntityManagerInView pattern LazyInitialization exception
Hi,
I'm trying to implement the OEMIV pattern but am running into problems. I've spent a few days trawling forum posts, but am not much the wiser. Essentially the transaction manager doesn't seem to be aware of the opened session.
I'm using Hibernate as the JPA implementation, and have separate bundles implementing the data model, and the actual vendor specific DAO. I've configured the entitymanager and transaction manager in the Hibernate DAO bundle and exposed them as services thus (only posting relevant bits):
Bean declaration
Code:
<bean id="testEMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="testDS"/>
<property name="persistenceUnitName" value="TestPU"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/>
<property name="generateDdl" value="false"/>
<property name="showSql" value="true"/>
</bean>
</property>
</bean>
<bean id="testTM" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="testEMF"/>
</bean>
Service export
Code:
<service ref="testTM" interface="org.springframework.transaction.PlatformTransactionManager"/>
<service ref="testEMF" interface="javax.persistence.EntityManagerFactory"/>
I've defined my webapp application context in applicationContext.xml and test-console-servlet.xml with contents as follows (omitting namespace declarations):
applicationContext.xml
Code:
<osgi:reference id="componentSvc"
interface="org.tssg.test.dataaccess.service.ComponentService" />
<osgi:reference id="testEMF"
interface="javax.persistence.EntityManagerFactory" />
test-console-servlet.xml
Code:
<context:component-scan base-package="org.tssg.test.web.dashboard.web" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
web.xml (relevant bits)
Code:
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<init-param>
<param-name>entityManagerFactoryBeanName</param-name>
<param-value>testEMF</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextClass</param-name>
<param-value>com.springsource.server.web.dm.ServerOsgiBundleXmlWebApplicationContext</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>test-console</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>test-console</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
I'll post the log output in a reply, as if I include it here, I run into the 10k limit, so I'll comment on that there.
I've also attached a stripped down Maven project that should hopefully import cleanly if anybody wants to try it. I'm deploying to DM Server btw
(to be continued)
John McLaughlin
Still stuck, but found possible cause
Hi all,
I've come back to this problem as I've got no further tinkering with configurations. I tried to externalise the EntityManagerFactory as suggest in this thread to no avail.
To try to get to the bottom of the problem, I've started to single step through the code for JpaTransactionManager, and OpenEntityManagerInViewFilter and have found what may be a bug.
Both EntityManagerInViewFilter and JpaTransactionManager make use of TransactionSynchronizationManager and use the EntityManagerFactory as a key. Both TransactionSynchronizationManager.bindResource() and TransactionSynchronizationManager.getResource() call TransactionSynchronizationUtils.unwrapResourceIfNe cessary() with the EMF bean (proxies in both cases). That method is shown here:
Code:
static Object unwrapResourceIfNecessary(Object resource) {
Assert.notNull(resource, "Resource must not be null");
Object resourceRef = resource;
// unwrap infrastructure proxy
if (resourceRef instanceof InfrastructureProxy) {
resourceRef = ((InfrastructureProxy) resourceRef).getWrappedObject();
}
if (aopAvailable) {
// now unwrap scoped proxy
resourceRef = ScopedProxyUnwrapper.unwrapIfNecessary(resource);
}
return resourceRef;
}
A sample of what happens is as follows. For OEMIVF, the resource is for example $Proxy283. After calling ((InfrastructureProxy) resourceRef).getWrappedObject() resourceRef is $Proxy270. For JpaTM resource is $Proxy269, and post unwrapping resourceRef is $Proxy270.
This would be wonderful if these were returned at this point, HOWEVER the method trundles on to
Code:
resourceRef = ScopedProxyUnwrapper.unwrapIfNecessary(resource)
which results in resourceRef being trampled by the original resource param, as the bean in question isn't and AOP proxy and thus not unwrapped in the SPU unwrap method.
Is this a bug or a "feature"? If the former, should I raise a JIRA, and if the latter (actually in either case), can anybody suggest a workaround?
DM Server version is 2.0.1-RELEASE implying Spring Framework 3.0.0-RELEASE and Spring DM 1.2.1
Regards,
John