7

I used to have all my DAOs extend the JdoDaoSupport class which is now deprecated in Spring 3.1. I've made my own AbstractJdoDao class which wraps the PersistenceManagerFactory and all the DAOs extend from there. Is that the way I should be doing?

Also in the documentation on JDO, it seems that the direct instantiation of PersistenceManagerFactory is not the default option, but to use LocalPersistenceManagerFactoryBean wrapped in a TransactionAwarePersistenceManagerFactoryProxy. How to properly instantiate these beans and make them work with the Spring's @Transactional annotations.

Here's the persistence-related part of my application context:

<bean id="persistenceManagerFactoryProxy" class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
    <property name="targetPersistenceManagerFactory">
        <bean class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
            <property name="jdoPropertyMap">
                <props>
                    <prop key="javax.jdo.PersistenceManagerFactoryClass">org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory</prop>
                    <prop key="javax.jdo.option.ConnectionURL">appengine</prop>
                    <prop key="javax.jdo.option.NontransactionalRead">true</prop>
                    <prop key="javax.jdo.option.NontransactionalWrite">false</prop>
                    <prop key="javax.jdo.option.RetainValues">false</prop>
                    <prop key="javax.jdo.option.DetachAllOnCommit">true</prop>
                    <prop key="javax.jdo.option.Multithreaded">true</prop>
                    <prop key="datanucleus.appengine.ignorableMetaDataBehavior">NONE</prop>
                </props>
            </property>
        </bean>
    </property>
    <property name="allowCreate" value="false" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager" class="org.springframework.orm.jdo.JdoTransactionManager">
    <property name="persistenceManagerFactory" ref="persistenceManagerFactoryProxy" />
</bean>

Now when I load a page accessing the data store:

org.springframework.transaction.CannotCreateTransactionException: Could not open JDO PersistenceManager for transaction; nested exception is java.lang.IllegalStateException: No JDO PersistenceManager bound to thread, and configuration does not allow creation of non-transactional one here
    at org.springframework.orm.jdo.JdoTransactionManager.doBegin(JdoTransactionManager.java:369) ~[spring-orm-3.1.0.RELEASE.jar:3.1.0.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371) ~[spring-tx-3.1.0.RELEASE.jar:3.1.0.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335) ~[spring-tx-3.1.0.RELEASE.jar:3.1.0.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105) ~[spring-tx-3.1.0.RELEASE.jar:3.1.0.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.1.0.RELEASE.jar:3.1.0.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) ~[spring-aop-3.1.0.RELEASE.jar:3.1.0.RELEASE]
    at $Proxy15.queryAll(Unknown Source) ~[na:na]
    ...
Caused by: java.lang.IllegalStateException: No JDO PersistenceManager bound to thread, and configuration does not allow creation of non-transactional one here
    at org.springframework.orm.jdo.PersistenceManagerFactoryUtils.doGetPersistenceManager(PersistenceManagerFactoryUtils.java:153) ~[spring-orm-3.1.0.RELEASE.jar:3.1.0.RELEASE]
    at org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy$PersistenceManagerFactoryInvocationHandler.invoke(TransactionAwarePersistenceManagerFactoryProxy.java:159) ~[spring-orm-3.1.0.RELEASE.jar:3.1.0.RELEASE]
    at $Proxy13.getPersistenceManager(Unknown Source) ~[na:na]
    at org.springframework.orm.jdo.JdoTransactionManager.doBegin(JdoTransactionManager.java:308) ~[spring-orm-3.1.0.RELEASE.jar:3.1.0.RELEASE]
... 73 common frames omitted

I've got my example project on GitHub. It's using Google App Engine, so either run it via mvn gae:run in Eclipse (with the Google Plugin for Eclipse), first creating an Eclipse project via mvn eclipse:eclipse.

hleinone
  • 4,400
  • 3
  • 33
  • 48
  • Reading the documentation, I conclude that the property "persistenceManagerFactory" of the bean "transactionManager" should reference the bean "LocalPersistenceManagerFactoryBean" instead of the proxy. So you need to give that bean an id, instead of being anonymous as in your example. – Luciano Jan 26 '12 at 13:20

1 Answers1

3

My suggestion would be to use TransactionAwarePersistenceManagerFactoryProxy or SpringPersistenceManagerProxyBean as suggested by the Spring 3.1 documentation. It seems that this is designed to replace the JdoDaoSupport class.

While what you're suggesting in your question of creating your own AbstractJdoDao wrapper will of course eliminate the deprecation warning, my only concern is that you may inadvertently create a situation that's hard for others to maintain as it won't be what they are used to seeing.

On the other hand, I imagine creating your own wrapper is a very fast way to solve your problem...

You should carefully weigh the advantages/disadvantages of using your own wrapper with the advantages/disadvantages of moving forward with the Spring 3.1 way of doing things. In my experience, taking shortcuts can and oftentimes do come back to haunt you in the future.

jmort253
  • 32,054
  • 10
  • 92
  • 114
  • Should the `AbstractJdoDao` then rather have a reference to `TransactionAwarePersistenceManagerFactoryProxy` than `PersistenceManagerFactory`? – hleinone Jan 28 '12 at 16:42
  • Yes, you are correct. The examples they're using in the [Spring 3.1 JDO documentation](http://static.springsource.org/spring/docs/3.1.0.RC1/spring-framework-reference/html/orm.html#orm-jdo-daos-straight) show the PersistenceManagerFactory injected into your Dao class using a TransactionAwarePersistenceManagerFactoryProxy object. I guess you could inject that into an abstract class and inherit from it just the same; however, they're not using an abstract class in the examples. According to the docs, the advantage of this method is that you're not using any Spring dependencies. – jmort253 Jan 28 '12 at 20:43
  • I isolated the problem into a [project on GitHub](https://github.com/hleinone/spring-gae-jdo). Still ending up with pretty much the same exception. – hleinone Jan 30 '12 at 15:28
  • I have now solved the problem in the example project. In the end it was mostly misconfiguration, but your answer really helped me in solving that. – hleinone Feb 08 '12 at 19:57
  • Glad I was able to help! Thanks for the feedback :) – jmort253 Feb 08 '12 at 23:17