Blogs

SpringSource Blog

Migrating to Spring 3.1 and Hibernate 4.1

Michael Isvy

Update to Spring 3.2
The application has been updated to Spring 3.2. The new version is available here: Spring 3.2. The old one is still available: Spring 3.1.

As part of the Core-Spring course, we have a lab application that we use to show how to integrate Spring and JPA/Hibernate together. We have just upgraded it to Spring 3.1 / Hibernate 4.1, and thought we should share a few tips.

1) Maven Dependencies

The configuration sample below is based on Maven (but you can easily convert it to Gradle if needed). Inside your POM, you should specify the latest versions of Spring and Hibernate (you might need to declare more Spring dependencies depending on which Spring components you're using).


<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-orm</artifactId>
     <version>3.2.0.RELEASE</version>
     <!-- will come with all needed Spring dependencies such as spring-core and spring-beans-->
</dependency>
<dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-entitymanager</artifactId>
     <version>4.1.9.Final</version>
     <!-- will come with Hibernate core-->
</dependency>

The cglib dependency is not always needed. You will find more details on that at the end of this blog entry.

2.a) Spring configuration for Hibernate

Spring provides support for several versions of Hibernate, so you need to specify explicitly which version you're using.

With Hibernate 4:

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
     <property name="sessionFactory" ref="sessionFactory"/>
</bean>

If you were to work with Hibernate 3, you would have instead:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
...
</bean>

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
     <property name="sessionFactory" ref="sessionFactory"/>
</bean>

(the package path is different according to whether you wish to use Hibernate 3 or Hibernate 4)

When working with Hibernate, there are 2 common ways of writing your mapping: XML and annotations.

Spring-Hibernate 3 integration allows you to configure 2 kinds of SessionFactoryBean:

  • LocalSessionFactoryBean for xml mapping only
  • AnnotationSessionFactoryBean for xml mapping and/or Annotation-based mapping

With Spring 3.1 and Hibernate 4, things are now simpler: there is only one SessionFactoryBean called LocalSessionFactoryBean.
It works with both annotation-based mapping and xml-based mapping.

If you followed those 2 steps carefully, you should have a running application already.

2.b) Spring configuration for JPA

As an alternative of using Hibernate directly, you can also use JPA as an abstraction layer on top of Hibernate. Here is an example:

<jdbc:embedded-database id="dataSource">
 <jdbc:script location="classpath:jpa/config/schema.sql" />
 </jdbc:embedded-database>

 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="persistenceUnitName" value="jpaTest" />
    <property name="packagesToScan">
    <list>
       <value>jpa/config</value>
    </list>
    </property>
    <property name="jpaVendorAdapter">
       <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
          <property name="database" value="HSQL" />
       </bean>
    </property>
 </bean>

 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
 </bean>

3) Do you need that CGLIB dependency?

The answer is likely to be a "yes". It is actually common that Spring would need it under the hood. Here are some examples:

  • Java configuration (more info here)
  • Adding features such as Transactional behavior, Security, Caching… to a Spring bean that does not implement an interface (more information here)
  • When the @Transactional annotation is used inside a JUnit Test case (you usually do that so the database transaction can rollback at the end of each test case, see here for more details).

4) Java Configuration

Using Java Configuration with Spring is an interesting alternative to xml-based and annotation-based configuration.
So how to work with Spring and Hibernate using Java configuration? A new class called LocalSessionFactoryBuilder makes things pretty easy.

@Bean
public SessionFactory sessionFactory() {
 return new LocalSessionFactoryBuilder(dataSource())
 .addAnnotatedClasses(Person.class, Account.class)
 .buildSessionFactory();
}

LocalSessionFactoryBuilder subclasses Hibernate's own Configuration class, and as the name suggests, provides a convenient builder-style API for use within Spring @Configuration classes.

 

All the above code samples are available here: https://github.com/michaelisvy/hibernate-4-spring-3.1-samples

 

 

Similar Posts

Share this Post
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Slashdot
  • Technorati
  • Twitter
 

35 responses


  1. One problem I ran into when migrating to Spring 3.1 with Hibernate 4 is that the HibernateTemplate support in Spring 3.1 for Hibernate 4 is minimal and in fact slated for removal (see https://jira.springsource.org/browse/SPR-8096). Since my application was migrated from the days of Spring 2 and Hibernate 2, everything uses HibernateTemplate, thus the migration to Hibernate 4 requires a lot more work than just swapping JARs. I was able to take it to Spring 3.1 and Hibernate 3 with only minor changes. So as long as your application is not relying on HibernateTemplate, migration to Spring 3.1 and Hibernate 4 could be pretty straightforward, otherwise may be a much bigger task.


  2. Do you have more complete sample to this?


  3. How about configuration JPA Hibernate 4? can you write examples?


  4. development


  5. I prefer to configure JPA by using a LocalContainerEntityManagerFactoryBean in Java config.

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactory.setDataSource(dataSource());
    entityManagerFactory.setPackagesToScan(new String[] { "nl.pamisoft" });
    entityManagerFactory.setPersistenceProvider(new HibernatePersistence());

    return entityManagerFactory;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
    return new JpaTransactionManager(entityManagerFactory().getObject());
    }

    This way you use JPA factories only and no Hibernate specific ones.


  6. how can we configure these local session factory builder? as all the configuration functions returns configuration interface and there is no function to call build session factory on configuration. so if i write –
    SessionFactory sessionFactory = new LocalSessionFactoryBuilder(this.dataSource).addAnnotatedClasses(Item.class, Order.class) .setProperties(prop) .buildSessionFactory();

    I get buildsessionfactory deprecated as it refers to different function which takes service registry as input.

    And no tests are included for hibernate4 in spring framework –
    https://github.com/SpringSource/spring-framework/tree/master/spring-orm/src/test/java/org/springframework/orm


  7. @Eric: indeed, the HibernateTemplate now is deprecated.

    @Sawan: please give me a few days and I'll share a complete example on my github account. I'll post a link here.

    @Menestry: I have added a code sample to show JPA and Hibernate 4.1 (see section 2.b).


  8. From where can we download updated source for this application ? any CVS or download path please ?


  9. To define JPA PlatformTransactionManager in Java config is important to specify Hibernate dialect and provide datasource, otherwise transactions with JdbcTemplate are broken

    @Bean
    public PlatformTransactionManager transactionManager() { JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory);
    transactionManager.setDataSource(dataSource);
    transactionManager.setJpaDialect(new HibernateJpaDialect());
    return transactionManager;
    }


  10. hopefully correctly formatted and with autowired dataSource

    @Bean
    @Autowired
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
    JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory);
    transactionManager.setDataSource(dataSource);
    transactionManager.setJpaDialect(new HibernateJpaDialect());
    return transactionManager;
    }


  11. I've added a sample project here:
    https://github.com/michaelisvy/hibernate-4-spring-3.1-samples


  12. Thanks I got the URL –
    https://github.com/michaelisvy/hibernate-4-spring-3.1-samples

    This example does not use Java Configuration (or LocalSessionFactoryBuilder)

    Can you try using the LocalSessionFactoryBuilder, as I didn't find any way to bind Hibernate properties to builder.

    Thanks,
    Sawan


  13. Hi,
    I have updated my samples so they now include Java configuration samples for both JPA and Hibernate config.
    Hopefully they contain all you need now :) .

    https://github.com/michaelisvy/hibernate-4-spring-3.1-samples


  14. Your JpaConfig is not correct – you autowire datasource in the configuration and define at the same time – should do only one of these.

    Please see below for correct version where the datasource bean is defined in the configuration and autowired, but to other bean definitions, not configuration.

    
    package jpa.config.java;
    
    import javax.persistence.EntityManagerFactory;
    import javax.sql.DataSource;
    
    import org.hibernate.ejb.HibernatePersistence;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean;
    import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    @Configuration
    @EnableTransactionManagement
    public class JpaConfig {
    
    	@Bean
    	@Autowired
    	public EntityManagerFactory entityManagerFactory(DataSource dataSource) {
    
    		LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
    		entityManagerFactory.setDataSource(dataSource);
    		entityManagerFactory.setPackagesToScan(new String[] { "jpa.config.java" });
    		entityManagerFactory.setPersistenceProvider(new HibernatePersistence());
    		entityManagerFactory.afterPropertiesSet();
    		return entityManagerFactory.getObject();
    	}
    
    	@Bean
    	@Autowired
    	public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory, DataSource dataSource) {
    		JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory);
    		transactionManager.setDataSource(dataSource);
    		transactionManager.setJpaDialect(new HibernateJpaDialect());
    		return transactionManager;
    	}
    
    	@Bean
    	public DataSource dataSource() {
    		EmbeddedDatabaseFactoryBean bean = new EmbeddedDatabaseFactoryBean();
    		ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
    		databasePopulator.addScript(new ClassPathResource("hibernate/config/java/schema.sql"));
    		bean.setDatabasePopulator(databasePopulator);
    		bean.afterPropertiesSet(); // necessary because
    									// EmbeddedDatabaseFactoryBean is a
    									// FactoryBean
    		return bean.getObject();
    	}
    
    /* other version of the same beans - no autowiring, CGLIB magic only
    
    	@Bean
    	public EntityManagerFactory entityManagerFactory() {
    
    		LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
    		entityManagerFactory.setDataSource(dataSource());
    		entityManagerFactory.setPackagesToScan(new String[] { "jpa.config.java" });
    		entityManagerFactory.setPersistenceProvider(new HibernatePersistence());
    		entityManagerFactory.afterPropertiesSet();
    		return entityManagerFactory.getObject();
    	}
    
    	@Bean
    	@Autowired
    	public PlatformTransactionManager transactionManager() {
    		JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory());
    		transactionManager.setDataSource(dataSource());
    		transactionManager.setJpaDialect(new HibernateJpaDialect());
    		return transactionManager;
    	}
    
    	@Bean
    	public DataSource dataSource() {
    		EmbeddedDatabaseFactoryBean bean = new EmbeddedDatabaseFactoryBean();
    		ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
    		databasePopulator.addScript(new ClassPathResource("hibernate/config/java/schema.sql"));
    		bean.setDatabasePopulator(databasePopulator);
    		bean.afterPropertiesSet(); // necessary because
    									// EmbeddedDatabaseFactoryBean is a
    									// FactoryBean
    		return bean.getObject();
    	}
    
    */
    
    }
    

  15. Thanx Petr I have just fixed this issue (both for JPA an Hibernate).


  16. I have not been able to get this to run.

    Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'transactionManager' defined in class jpa.config.java.JpaConfig: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.persistence.EntityManagerFactory]: : Error creating bean with name 'entityManagerFactory' defined in class jpa.config.java.JpaConfig: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.sql.DataSource]: : Error creating bean with name 'dataSource' defined in class jpa.config.java.JpaConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource jpa.config.java.JpaConfig.dataSource()] threw exception; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 2 of resource class path resource [hibernate/config/java/schema.sql]: create table T_ACCOUNT (id bigint generated by default as identity (start with 1), cashBalance double, name varchar(255), primary key (id)); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class jpa.config.java.JpaConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource jpa.config.java.JpaConfig.dataSource()] threw exception; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 2 of resource class path resource [hibernate/config/java/schema.sql]: create table T_ACCOUNT (id bigint generated by default as identity (start with 1), cashBalance double, name varchar(255), primary key (id)); nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactory' defined in class jpa.config.java.JpaConfig: Unsatisfied dependency expressed through constructor argument with index 0 of type [javax.sql.DataSource]: : Error creating bean with name 'dataSource' defined in class jpa.config.java.JpaConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource jpa.config.java.JpaConfig.dataSource()] threw exception; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 2 of resource class path resource [hibernate/config/java/schema.sql]: create table T_ACCOUNT (id bigint generated by default as identity (start with 1), cashBalance double, name varchar(255), primary key (id)); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class jpa.config.java.JpaConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource jpa.config.java.JpaConfig.dataSource()] threw exception; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to execute database script; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement at line 2 of resource class path resource [hibernate/config/java/schema.sql]: create table T_ACCOUNT (id bigint generated by default as identity (start with 1), cashBalance double, name varchar(255), primary key (id))

    I am assuming it is something wrong with my environment. Also, has anyone checked this out and ran it?

    Thank you,

    Dave


  17. Hi Dave,
    I have fixed a couple if issues (they were mostly due to misuse of git). But I haven't been able to reproduce the issue you're having. Could you do a "git pull" and try again, to see if it helps?


  18. Thanks for the example


  19. Thank you for this post, this is what I really needed.
    I had some problems with embedded HSQL for tests, until I grabbed the lastest version, just to notice that.


  20. Indeed, there was an issue with the SQL script, and I've fixed it in the latest commit.


  21. I have a Spring 3.1 Hibernate 4.0 application which is working fine in Tomcat 7. It is deployed as a .war file with the persistence.xml in the WEB-INF/classes/META-INF folder. The entities are auto-detected there.

    But when I deploy the application in JBoss AS 7.1.1.Final, the entities are not auto-detected. I have to explicitly list them in the persistence.xml.

    I think it as a JBoss problem. Have you come across similar queries?
    This link also says a similar issue
    https://community.jboss.org/message/646488


  22. @Rupesh
    Short answer because I'm on vacations…
    No I hadn't heard of it before. I have only tried on Tomcat, which works well like you mentioned.
    Please let us know if you there is a fix or a workaround for that!


  23. HibernateJpaDialect seems to be using org.springframework.orm.hibernate3.SessionFactoryUtils;

    Is this intentional? Is there any way to be able to specify which version of hibernate is being used?

    There's more detailed question on this thread:

    http://forum.springsource.org/showthread.php?127001-HibernateJpaDialect-coupled-to-SessionFactoryUtils-of-Hibernate-3


  24. It seems that HibernateJpaDialect uses SessionFactoryUtils of Hibernate3. Is there any to be able to configure JPA to use Hibernate4's SessionFactoryUtils so I get Hibernate4 exceptions?

    The following post on the forum has a more detailed question:

    http://forum.springsource.org/showthread.php?127001-HibernateJpaDialect-coupled-to-SessionFactoryUtils-of-Hibernate-3


  25. i was trying to follow you blog but it looks like my maven is still loading hibernate3 and hibernate4 can you please look at this

    http://stackoverflow.com/questions/12424423/upgrading-my-spring-webflow-projects-to-use-maven-and-hibernate4-now-gets-nosuc


  26. @J Smith: first of all I believe this is a Maven/libs issue, it has nothing to do with your Spring config which seems very much correct.

    Usually, in development mode, you shouldn't have any lib inside web-inf/lib. Eclipse/STS should refer to the jars that are inside your local repository instead.

    So may be you can try to:
    1) remove all the jars from src/main/webapp/WEB-INF/lib
    2) do "mvn package"
    3) open the archive and see what Maven has placed inside WEB-INF/lib

    Hope that helps!


  27. Michael,

    Is Spring Batch compatible with Hibernate 4? As far as I can tell the issue described here (http://stackoverflow.com/questions/12038980/java-lang-nosuchmethoderror-org-hibernate-sessionfactory-opensession) still applies.

    I'm facing the exact same issue, but then again, I may be configuring something the wrong way. I'm guessing I'm doing something wrong, since I don't see many similar reports over the internet.

    Thanks in advance.


  28. @Vincent: indeed, Spring Batch hasn't been migrated to Hibernate 4 yet.
    There is an issue opened for that here: https://jira.springsource.org/browse/BATCH-1904


  29. I have updated the sample application to Spring 3.2 (I haven't changed the title of this post because I suspect a few websites link to it).

    Moving to Spring 3.2 was straightforward (I only had to change the POM dependencies).


  30. Hi,

    If we wanna configure either the Jpa och Hibernate java configuration to include hbm2ddl, how would it be done? Tried for a while now cause I want the tables to be autocreated, I don't want it to run an initDB script everytime i run the application.

    tried to:
    Properties props = new Properties();
    props.setProperty("hibernate.hbm2ddl.auto", "drop-create");
    sessionFactoryBuilder.setProperties(props);

    But can't get it to work,

    Please bring some light in this.


  31. @Nicklas I don't have a working example of hbm2ddl as I don't use it much myself (I've had some bad experiences with the way it generates everything that is not explicitly specified in your mapping, such as names for foreign keys).
    I would suggest that you try to make it work first with xml rather Javaconfig as you're very much unlikely to find some working Javaconfig examples when googling around (Javaconfig is still much less widely used than XML/annotations).

    Cheers,
    Michael.


  32. Michael – thanks for the post.

    We are using Spring 3.2.1 and Hibernate 4.1.9 with XML config and JPA. I cannot see how you specify which version of Hibernate to use in your example, or on GitHub.

    We are getting a Hibernate 'Failed to convert to internal representation' error and I'm wondering if it is a Hibernate 3/4 issue.

    Hope you can help.
    Thanks
    Richard


  33. Hi Richard,
    the version of Hibernate is declared inside the pom.xml file.

    I can't recall having had a 'Failed to convert to internal representation' error before.

    Cheers,
    Michael.


  34. It troubles me to see XML configuration referred to in relation to Spring 3.2 training.

    No wonder we still have XML hell in so many enterprise projects! ;-)


  35. I think you should add transaction factory semantic change in upgrade notes.

    http://koenserneels.blogspot.com/2012/05/migrating-from-hibernate-3-to-4-with.html

3 trackbacks

Leave a Reply