Overview
At some point of time, as your project scope grows, the Hibernate mapping XML files are going to get to a point where it becomes very difficult to maintain. This is where the annotation-based configuration comes in. It took me a few years to convince myself that annotation-based configuration is the way to go. Change is hard, yet necessary.
This tutorial covers the following:-
- Upgrade Hibernate from 3.x to 4.x.
- Configure Spring-Hibernate integration to replace XML-based configuration with annotation-based configuration.
- Configure Joda-Time to work properly in Hibernate 4.
- Activate
@Transactional
instead of relying on AOP-based transaction.
Maven Dependencies
Change the Hibernate dependency version from 3.x to 4.x. On top of that, add org.jadira.usertype:usertype.core:[version]
dependency to get Joda-Time to work properly with Hibernate 4.
Hibernate 3.x
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.9.Final</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.3</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time-hibernate</artifactId> <version>1.3</version> </dependency>
Hibernate 4.x
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.2.6.Final</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.3</version> </dependency> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time-hibernate</artifactId> <version>1.3</version> </dependency> <dependency> <groupId>org.jadira.usertype</groupId> <artifactId>usertype.core</artifactId> <version>3.1.0.CR8</version> </dependency>
By the way, if you don’t know what Joda-Time is or haven’t use it by now, then you should be spanked by the Date God. With that added dependency, the @Type
for date field will look a little different ( see here for more info ):-
@Entity @Table(name = "MrMeow") public class MrMeow implements Ideable, Serializable { ... @Column @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate") private LocalDate whenMeowed; }
Spring Integration
Hibernate 3.x
This configuration uses Hibernate XML mapping files to configure mappings between the domain objects and the database tables. Further, AOP is used to configure the transaction.
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:hibernate.cfg.xml"/> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <tx:advice id="txAdvice"> <tx:attributes> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config proxy-target-class="true"> <aop:advisor pointcut="execution(* myproject..*.*(..))" advice-ref="txAdvice"/> </aop:config>
Hibernate 4.x
This configuration scans myproject.domain
package, which contains all Hibernate annotated domain classes. Further, it activates @Transactional
so that you can place it in your code to manage the transaction.
<tx:annotation-driven transaction-manager="transactionManager"/> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="hibernateProperties"> <props> <!-- Configure your Hibernate dialect --> <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop> <prop key="hibernate.show_sql">false</prop> </props> </property> <property name="packagesToScan"> <list> <!-- Configure your domain package --> <value>myproject.domain</value> </list> </property> </bean>
web.xml
Change filter class for OpenSessionInViewFilter
.
Hibernate 3.x
<filter> <filter-name>hibernateFilter</filter-name> <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Hibernate 4.x
<filter> <filter-name>hibernateFilter</filter-name> <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Domain Classes
Finally, time to annotate your Hibernate domain classes!
Helpful Note
Please make sure you don’t have JPA 1.x in your classpath in the first place. Read java.lang.NoSuchMethodError: javax/persistence/OneToMany.orphanRemoval()Z for more information.