Configuring JDO in Spring 3.1? - java

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.

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.

Related

spring migration 4 to 5; what is causing java.lang.ClassNotFoundException: org.springframework.orm.hibernate4.LocalSessionFactoryBean

I am migrating an old app from Spring 4 to 5. It builds fine with Maven, but when I start the app in jboss 7.1, I get this error:
java.lang.ClassNotFoundException: org.springframework.orm.hibernate4.LocalSessionFactoryBean
Spring 5.3.20
Hibernate 5.3.28.Final
I have been following this guide, https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-5.x
This said Hibernate 5 is required, so I updated that in the pom to 5.3.28.Final
Here is relevant snippet of spring-context.xml:
<bean id="hibernateSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.mycompany.bean.FooService</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="show_sql">true</prop>
</props>
</property>
</bean>
Running with Java 8.
You need to replace org.springframework.orm.hibernate4.LocalSessionFactoryBean with org.springframework.orm.hibernate5.LocalSessionFactoryBean.
The relevant parts of the migration guide are:
Hibernate support has been upgraded to a Hibernate ORM 5.2+ baseline, with a focus on ORM 5.4.x.
This indicates that the minimum version of Hibernate is now Hibernate 5.2.
and
Packages web.view.tiles2 and orm.hibernate3/hibernate4 dropped.
This indicates that the package your XML config is using (org.springframework.orm.hibernate4) no longer exists. Searching for LocalSessionFactoryBean in the Spring Framework 5.3.22 apidoc shows org.springframework.orm.hibernate5.LocalSessionFactoryBean. Its API seems compatible with your XML definition, so changing the class property should be all that you need to change.

Event listeners on hibernate 5

I'm updating my hibernate from version 3 to 5 and I have in my application context I had the following bean
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
p:mappingResources="standard.hbm.xml">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
<prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<property name="eventListeners">
<map>
<entry key="merge">
<bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
</entry>
</map>
</property>
</bean>
The problem is in hibernate 5 I don't have EventListners and also I don't have IdTransferringMergeEventListener. Do I need this? How can I replace?
from api IdTransferringMergeEventListener
Extension of Hibernate's DefaultMergeEventListener, transferring the
ids of newly saved objects to the corresponding original objects (that
are part of the detached object graph passed into the merge method).
So if you don't use this in your project you can skip it. If you need it , you can just copy listener and register one. I think DefaultMergeEventListener has method onMerge(MergeEvent event, Map copiedAlready) that support old IdTransferringMergeEventListener
from IdTransferringMergeEventListener extends org.hibernate.event.def.DefaultMergeEventListener, which has been moved to org.hibernate.event.internal.DefaultMergeEventListener it should be ok.
We intentionally kept Spring's Hibernate 4 support rather minimal, in
order to stay close to the native Hibernate 4 ways of doing things. As
a consequence, we have no plans to reintroduce
IdTransferringMergeEventListener or any of our former LOB user types,
all of which were special-purpose classes to work around issues that
Hibernate should really solve itself - since they have nothing to do
with Spring and caused repeated maintenance headaches on Spring's
side.
You're free to create your own version based on Spring's old
IdTransferringMergeEventListener, of course. However, note that the
way that event listeners can be registered has changed in Hibernate 4:
This is not possible on a per-SessionFactory level anymore, hence
Spring cannot support in its LocalSessionFactoryBean either. Check the
corresponding Hibernate documentation and the corresponding reports on
the Hibernate JIRA for details.

Jersey Service Initialization with HIbernate default dataset

I have a stack that consists of Hibernate, Spring, and Jersey.
While a great deal of things are RESTFUL, not everything in our application is (and cannot be, for various reasons. I realize I break REST best practices in places.)
I need to do two things and cannot figure out how to make both happen.
in my application-context.xml I have the following
<!-- Configure the entity manager factory bean -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
<property name="packagesToScan" value="com.mystuff.model"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.import_files">data.sql</prop>
</props>
</property>
This normally loads some hibernate data into the database for me.
However, I also need to initialize some in memory structures in the service.
The moment i try to have my service extend ServletContainer and override initiate despite a call to super.initiate()
or implement AbstractResourceModelListener and then provide onLoaded(AbstractResourceModelContext modelContext)
I am getting null pointers because my initial data provided by data.sql is not there.
How can I do this correctly so I both get my data.sql loaded and can execute a few statements when the service is loaded?
(If anyone is curious, yes the service is a #Singleton)
Any help appreciated.
So, it turns out the right answer here, is to use #PostConstruct despite the warnings eclipse may give you about restrictions and libraries. I'm not sure why that warning appears, or why it proceeds to work anyways, but #PostConstruct is the way to go to not trash other loading in Spring.
(That said, if you aren't pinned in, doing the initialization outside and injecting it is more RESTFUL and better and not needing #Singleton, but I assume in both the question and answer that it isn't an option for you for whatever reason.)

Hibernate ASM Spring java.lang.NoSuchMethodError sessionFactory

I think i already know what is the problem. i keep getting this error
org.springframework.beans.factory.BeanCreationException:
Could not autowire method: public void proTurism.DAO.AbstractDAO.setSession(org.hibernate.SessionFactory); nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]:
Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.objectweb.asm.ClassWriter.<init>(I)V
The problem shoulb be of 2 uncompatible ASM versions one using spring and one hibernate. i have hibernate ASM(unknown version packed in netbeans 7.1) and spring ASM(3.0.6). but i havent found any solution on how to get one asm or anything to get it working in glassfish with netbeans.
my applicationcontext.xml
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="proTurism"/>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
That's a tough dependency problem. You can only solve it if your two libraries (hibernate and spring) depend either on the same version of ASM, or on non-conflicting versions of ASM in terms of the functionality used. If that is not the case, upgrade/downgrade spring/hibernate until it works.
If using Maven, it will automatically show you which artifact requires which versions of its dependencies and it will be easier to trace and play with. Even if not using maven, you can still check the pom definitions of hibernate and spring to see which versions of asm they work with.

Migrating application context configuration to Spring 3.1 and Hibernate 4.0

I'm having hard time finding migration docs. I was using sping 3.0.5 and hibernate 3.4.
I migrated to the latest release candidates: spring 3.1 and hibernate 4.0
I was able to refactor my classes without problem but the application context for hibernate is giving me problems since I have not see any examples on how to configure it.
Specifically:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>...</list>
</property>
<property name="hibernateProperties">
<props>
...
<prop key="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</prop>
<prop key="hibernate.cache.provider_class">????</prop>
...
</props>
</property>
</bean>
Apparently properties dataSource , mappingResources and hibernateProperties no longer exist and I'm not so sure about what to put in hibernate.connection.provider_class and hibernate.cache.provider_class.
And I keep getting:
Caused by: java.lang.ClassNotFoundException: org.hibernate.engine.FilterDefinition
at application start.
To my knowledge, Spring has no support for Hibernate 4. If it did, I'd expect to see an org.springframework.orm.hibernate4 package in the 3.1.x package list, but it's not there. I don't believe I've seen any mention of it in any release notes or anything, either.
In other words, Spring is working fine, but you're using an incompatible version of Hibernate.
dataSource still exists, based on the JavaDoc for LocalSessionFactoryBean. See the section at the very top; it has an example config with a dataSource property. mappingResources also exists.
The Spring 3.1 reference guide also has an example, with dataSource and mappingResources.
Hibernate 4 does not have a ref guide yet.

Categories