Friday, February 24, 2012

Spring-Hibernate Integration

If we carefully look at the DAO methods, we see that we do some things repeatedly - open and close session and transaction.

Why not let someone else worry about this? It will reduce chances of programing errors and reduce the code we need to write.

Spring provides a Hibernate integration which can take care of this elegantly.

You configure the Hibernate related specifications in the Spring configuration XML. Then declare the DAO as a Spring bean.

Let us see how.

In your /classes folder, create a file spring-hibernate.xml, like this:
 <beans xmlns="http://www.springframework.org/schema/beans"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean id="confuciusDS" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/confuciusDB"/>
<property name="username" value="confucius"/>
<property name="password" value="changeit"/>
</bean>

<bean id="confuciusSF" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="confuciusDS"/>
<property name="mappingResources">
<list>
<value>./hibernate-beans/Item.hbm.xml</value>
<value>./hibernate-beans/Cart.hbm.xml</value>
<value>./hibernate-beans/User.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>hibernate.dialect=org.hibernate.dialect.MySQLDialect</value>
</property>
</bean>

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="confuciusSF"/>
</property>
</bean>

<import resource="spring-beans/bean-userDAO.xml" />
</beans>


This is all boiler-plate Spring-Hibernate configuration.

We have told Spring about our DataSource, how to connect to it to create a Session factory, and eventually to create HibernateTemplate - which is the only thing we will need from now.

Now we declare UserDAO as a Spring bean.
In your /classes/spring-beans/ folder, create a file bean-userDAO.xml, like this:
 <beans xmlns="http://www.springframework.org/schema/beans"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean id="userDAO" class="org.confucius.UserDAO">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
</beans>

As you can see, we are injecting HibernateTemplate into UserDAO.

Now update your UserDAO.java to contain a field heibernateTemplate, with its getters/setters so Spring can inject it.

Also, all the DAO methods will get updated to use hibernatetemplate.
Like this:
 package org.confucius;   

import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateTemplate;

public class UserDAO {
private HibernateTemplate hibernateTemplate;

public void setHibernateTemplate(HibernateTemplate hibernateTemplate){
this.hibernateTemplate = hibernateTemplate;
}

public HibernateTemplate getHibernateTemplate(){
return hibernateTemplate;
}

// Criteria with Restrictions
public List<User> getUsers (String firstName, String lastName) throws Exception{
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(User.class)
.add(Restrictions.eq("firstName", firstName))
.add(Restrictions.eq("lastName", lastName));

return ((List<User>) hibernateTemplate.findByCriteria(detachedCriteria));
}


// HQL with parameters
public List<User> getUsers (String firstName) throws Exception{
return ((List<User>) hibernateTemplate.find("from User where firstName=?", firstName));
}

// HQL with no parameters
public List<User> getUsers () throws Exception{
return ((List<User>) hibernateTemplate.find("from User"));
}


// Getting an object given its Id
public User getUser (long userId) throws Exception{
return ((User) hibernateTemplate.find("from User where id=?", userId));
}


// Persist
public void persist (User user) throws Exception{
hibernateTemplate.persist(user);
}
}


As you can see, our DAO methods have become considerable more simple, literally one-liners!

This is because Spring is taking care of Sessions and Transactions.

Update your TestPersistence.java to use the new UserDAO, like this:
 package org.confucius;   

import java.util.Iterator;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class TestPersistence {

public static void main(String[] args) {
try {
ApplicationContext springContext = new ClassPathXmlApplicationContext("spring-hibernate.xml");
UserDAO userDAO = (UserDAO) springContext.getBean("userDAO");

List<User> users = userDAO.getUsers("Joe", "Trumpet");
for (Iterator<User> iter = users.iterator(); iter.hasNext();)
System.out.println(iter.next());

} catch (Exception e) {
e.printStackTrace();
}
}
}

R-click on TestPersistence.java in Eclipse Navigator view.
Select Run As -> Java Application.

You will see Joe Trumpet printed to the console, along with contents of his cart.

Note, I had to use Hibernate3 (instead of Hibernate4) because of Spring issues with Hibernate4. I also needed a few other jars.

My ivy.xml now looks like this:

 <ivy-module version="2.0">  
<info organisation="org.confucius" module="helloworld"/>
<dependencies>
<dependency org="org.springframework" name="spring" rev="2.5.6"/>
<dependency org="commons-pool" name="commons-pool" rev="20030825.183949"/>
<dependency org="commons-dbcp" name="commons-dbcp" rev="20030825.184428"/>
<dependency org="antlr" name="antlr" rev="20030911"/>
<dependency org="javassist" name="javassist" rev="3.12.1.GA"/>
<dependency org="mysql" name="mysql-connector-java" rev="5.1.18"/>
<dependency org="javax.persistence" name="persistence-api" rev="1.0.2"/>
<dependency org="jboss" name="jboss-j2ee" rev="4.2.2.GA"/>
<dependency org="org.jboss.logging" name="jboss-logging" rev="3.1.0.GA"/>
<dependency org="org.slf4j" name="slf4j-simple" rev="1.6.1"/>
<dependency org="org.slf4j" name="slf4j-api" rev="1.6.4"/>
<dependency org="org.hibernate" name="hibernate3" rev="3.6.0.Final"/>
<dependency org="dom4j" name="dom4j" rev="1.6.1"/>
<dependency org="struts" name="struts" rev="1.2.9"/>
<dependency org="org.apache.struts" name="struts-taglib" rev="1.3.10"/>
<dependency org="commons-collections" name="commons-collections" rev="20040616"/>
<dependency org="commons-digester" name="commons-digester" rev="2.1"/>
<dependency org="commons-beanutils" name="commons-beanutils" rev="20030211.134440"/>
<dependency org="commons-logging" name="commons-logging" rev="1.1.1"/>
<dependency org="org.apache.httpcomponents" name="httpcore" rev="4.2-alpha2"/>
<dependency org="org.apache.httpcomponents" name="httpclient" rev="4.2-alpha1"/>
<dependency org="org.apache.commons" name="commons-exec" rev="1.1"/>
<dependency org="com.google.guava" name="guava" rev="r09"/>
<dependency org="org.seleniumhq.selenium" name="selenium-api" rev="2.17.0"/>
<dependency org="org.seleniumhq.selenium" name="selenium-remote-driver" rev="2.17.0"/>
<dependency org="org.seleniumhq.selenium" name="selenium-firefox-driver" rev="2.17.0"/>
<dependency org="org.seleniumhq.selenium" name="selenium-java" rev="2.16.1"/>
<dependency org="junit" name="junit" rev="4.10"/>
<dependency org="org.json" name="json" rev="20090211"/>
<dependency org="javax.servlet" name="servlet-api" rev="2.5"/>
<dependency org="javax.servlet" name="jsp-api" rev="2.0"/>
<dependency org="jstl" name="jstl" rev="1.2"/>
<dependency org="log4j" name="log4j" rev="1.2.16"/>
</dependencies>
</ivy-module>

No comments: