Spring 3.0 and Hibernate tutorial (part 1)

In my previous spring tutorial, i’ve given simple example how to integrating Spring Framework with Hibernate through JPA. Now i’ll show you how to engaging Spring with Hibernate using Hibernate template on Spring. It’s easier than you connect using JPA. Because spring already build hibernate support.

First of all, we need to create entity class. Lets give  it User class, this will be  located on org.adit.spring.hibernate.entity package. Following is the content of User.java

package org.adit.spring.hibernate.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "user")
public class User implements Serializable {
	/**
	 *
	 */
	private static final long serialVersionUID = 8496087166198616020L;
	private String userId;
	private String userName;
	private Integer age;
	private Boolean registered;

	@Id
	@GeneratedValue(generator = "system-uuid")
	@GenericGenerator(name = "system-uuid", strategy = "uuid")
	@Column(name = "userId")
	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}
	@Column(name = "userName", nullable=false)
	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}
	@Column(name = "age")
	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}
	@Column(name = "registered", nullable=false)
	public Boolean getRegistered() {
		return registered;
	}

	public void setRegistered(Boolean registered) {
		this.registered = registered;
	}
}

As you can see, i’m using generator approach, so Id of this record on database will automatically created , so you don’t need to set this entity Id or make this field auto generated when you create the table.

Second, we created DAO class, because just like  i told you before it gonna be simple example. So we just only create 4 basic method. Create, Retrtieve, Update and Delete (CRUD). Below is the interface of UserDao.java

package org.adit.spring.hibernate.dao;

import java.util.List;

import org.adit.spring.hibernate.entity.User;

public interface UserDao {
	public void saveUser(User user);
	public List<User> getAllUser(User user);
	public User selectUserById(String userId);
	public void deleteUser(User user);
}

And, we have to implement this interface with this class

package org.adit.spring.hibernate.dao;

import java.util.List;

import org.adit.spring.hibernate.entity.User;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

//This will make easier to autowired
@Repository("userDao")
// Default is read only
@Transactional
public class UserDaoImpl implements UserDao {
	private HibernateTemplate hibernateTemplate;

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		hibernateTemplate = new HibernateTemplate(sessionFactory);
	}

	@Transactional(readOnly = false)
	public void saveUser(User user) {
		hibernateTemplate.saveOrUpdate(user);

	}

	@Transactional(readOnly = false)
	public void deleteUser(User user) {
		hibernateTemplate.delete(user);

	}

	@SuppressWarnings("unchecked")
	public List<User> getAllUser(User user) {
		return (List<User>) hibernateTemplate.find("from "
				+ User.class.getName());
	}

	public User selectUserById(String userId) {
		return hibernateTemplate.get(User.class, userId);
	}

}

Class UserDaoImpl have added @Repository annotation, so we don’n need to write this dao into Spring beans configuration. This class already auto scanned.

Ok now, we created Spring configuration file. I deliberately separated configuration into small pieces, so it’s will easier for us, when maintenance or change our code in the future. Main configuration is app-config.xml. Contains general configuration for application.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<bean id="propertyConfigurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>/configuration.properties</value>
			</list>
		</property>
	</bean>

	<context:component-scan base-package="org.adit.spring" />
	<import resource="db-config.xml" />
</beans>

Second configuration is db-config.xml. This file purposes for saving configuration of datasource and ORM settings.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
	">
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
		destroy-method="close">

		<property name="driverClass">
			<value>${jdbc.driver.className}</value>
		</property>
		<property name="jdbcUrl">
			<value>${jdbc.url}</value>
		</property>
		<property name="user">
			<value>${jdbc.username}</value>
		</property>
		<property name="password">
			<value>${jdbc.password}</value>
		</property>
	</bean>
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="packagesToScan" value="org.adit.spring.hibernate.entity" />
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">${jdbc.hibernate.dialect}</prop>
				<prop key="hibernate.hbm2ddl.auto">create</prop>
				<!-- uncomment this for first time run-->
				<prop key="hibernate.hbm2ddl.auto">create</prop>
				<prop key="hibernate.show_sql">false</prop>
			</props>
		</property>
	</bean>
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory">
			<ref bean="sessionFactory" />
		</property>
	</bean>
	<tx:annotation-driven />
</beans>

I suggest to separate editable property into different file. So when we have to edit or change some property only this configuration.properties is changed.

jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springhibernate
jdbc.username=yourusername
jdbc.password=yourpassword
jdbc.hibernate.dialect=org.hibernate.dialect.MySQLDialect

For the last, write an unit testing class, Spring has good support for JUnit, it makes us testing painless. This is our unit testing class

package test.adit.spring.hibernate;

import java.util.List;

import junit.framework.Assert;

import org.adit.spring.hibernate.dao.UserDao;
import org.adit.spring.hibernate.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( { "/app-config.xml" })
public class UserTest {
	private UserDao dao;

	@Autowired
	public void setDao(UserDao dao) {
		this.dao = dao;
	}

	@Test
	public void testCreateData() {
		int expectedResult = 1;
		User user = new User();
		user.setAge(23);
		user.setUserName("Adit");
		user.setRegistered(true);
		dao.saveUser(user);
		Assert.assertEquals(expectedResult, dao.getAllUser(new User()).size());
	}

	@Test
	public void testRetrieveData() {
		List<User> userList = dao.getAllUser(new User());
		Assert.assertEquals(1, userList.size());
		User userExpected = userList.get(0);
		User userResult = dao.selectUserById(userExpected.getUserId());
		Assert.assertEquals(userExpected.getUserId(), userResult.getUserId());
	}

	@Test
	public void testUpdateData() {
		List<User> userList = dao.getAllUser(new User());
		Assert.assertEquals(1, userList.size());
		User userExpected = userList.get(0);
		userExpected.setUserName("Singgih");
		dao.saveUser(userExpected);
		User userResult = dao.selectUserById(userExpected.getUserId());
		Assert.assertEquals(userExpected.getUserName(), userResult
				.getUserName());
	}

	@Test
	public void testDeleteData() {
		List<User> userList = dao.getAllUser(new User());
		Assert.assertEquals(1, userList.size());
		User userExpected = userList.get(0);
		dao.deleteUser(userExpected);
		User userResult = dao.selectUserById(userExpected.getUserId());
		Assert.assertEquals(userResult, null);
	}
}

You can browse mavenize source code of this tutorial here. Or check out directly using subversion using :

svn checkout http://the-nest.googlecode.com/svn/trunk/java/spring-hibernate1 spring-hibernate1

Next part i’ll show how to build relations between tables in database

About singgihpraditya

Gua cuma orang biasa, gak lebih , gak kurang. code maniac (i've been entrust all whole live just to make a good code)
This entry was posted in Java, Maven, Spring. Bookmark the permalink.

13 Responses to Spring 3.0 and Hibernate tutorial (part 1)

  1. A good tutorial indeed. A minor point – the test you’ve written using JUnit is strictly an “integration test” rather than a unit test. It is testing multiple tiers of your application.

    Still a good test, but it is important to distinguish unit from integration.

    Thanks for the tutorial!

    • singgihpraditya says:

      Thanks for your reviews
      You’re right, it’s better to call those test integration test rather than unit testing, i was testing group unit in per test.

  2. Gautam says:

    Very nice tutorial.

  3. Anton says:

    Have been having trouble using info in UserTest.java to develop a way to simply store a line in the database.
    Would like a simple load program to store a line.

    Always have had trouble with DAO.

    Thank you,

    Anton

  4. Anton says:

    Have resolved my mistakes after some researching.

    After creating context,ctx from ClassPathXmlApplicationContext:

    UserDao dao = (UserDao)ctx.getBean(UserDao.class);

    With a dao; the rest came easy.

    Thanks for the tutorial,

    Anton

  5. Pingback: Eric Blue’s Blog » Weekly Lifestream for July 18th

  6. rootman says:

    Hey!

    Very nice tutorial.
    I am a newbie in this stuff.
    The tutorial is very helpful
    However it is not working on,
    i am researching in order to correct the errors.
    Maybe Anton could share with the mistakes he was refering to.

    Yours

  7. Shubha says:

    Simple, neat and very good one. can follow easily. Just follow the steps above to set up Hibernate connection, saves so much of anyone’s time.

    Thanks for the tutorial.

  8. Reto says:

    Hi, thanks for posting this example. I cannot seem to resolve this problem, even after moving app-config.xml to various places. Do you know what is causing this:

    Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [app-config.xml]; nested exception is java.lang.NoClassDefFoundError: org/springframework/transaction/interceptor/TransactionInterceptor
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:412)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:212)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:81)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
    at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:280)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:304)

  9. Reto says:

    [RETO] — PLEASE NOTE: I can see the “java.lang.NoClassDefFoundError: org/springframework/transaction/interceptor/TransactionInterceptor” fine. It is like Spring cannot figure stuff out from the location of the app-config-xml file, per it’s indication:

    Unexpected exception parsing XML document from class path resource [app-config.xml]

    Thanks a million

  10. Reto says:

    Hi — I resolved the problem. Strangely enough, it was due to a missing jar: aopalliance.jar. Quite the strange error.

  11. pamela says:

    Hi Guys!
    I’ve troubles runing maven project in:
    http://the-nest.googlecode.com/svn/trunk/java/spring-hibernate1
    When I run mvn test I get four errors Messages:

    [INFO] Copying 1 resource
    [WARNING] POM for ‘javax.mail:mail:pom:1.4:compile’ is invalid.
    Its dependencies (if any) will NOT be available to the current build.
    [WARNING] POM for ‘javax.jms:jms:pom:1.1:compile’ is invalid.
    Its dependencies (if any) will NOT be available to the current build.
    [WARNING] POM for ‘com.sun.jdmk:jmxtools:pom:1.2.1:compile’ is invalid.
    Its dependencies (if any) will NOT be available to the current build.
    [WARNING] POM for ‘com.sun.jmx:jmxri:pom:1.2.1:compile’ is invalid.
    Its dependencies (if any) will NOT be available to the current build.
    [INFO] [compiler:compile {execution: default-compile}]
    [INFO] Compiling 3 source files to /home/humberto/java/Dao/spring-hibernate1/target/classes
    [INFO] ————————————————————————
    [ERROR] BUILD FAILURE
    [INFO] ————————————————————————
    [INFO] Compilation failure
    error: error reading /home/humberto/.m2/repository/javax/mail/mail/1.4/mail-1.4.jar; error in opening zip file
    error: error reading /home/humberto/.m2/repository/javax/jms/jms/1.1/jms-1.1.jar; error in opening zip file
    error: error reading /home/humberto/.m2/repository/com/sun/jdmk/jmxtools/1.2.1/jmxtools-1.2.1.jar; error in opening zip file
    error: error reading /home/humberto/.m2/repository/com/sun/jmx/jmxri/1.2.1/jmxri-1.2.1.jar; error in opening zip file

    can anybody tell me how to correct pom.xml file or where download it?

  12. paul says:

    great post. i wanna share also a spoon-feed tutorial on Spring MVC

    http://www.adobocode.com/spring/a-spring-web-mvc-tutorial

    and add step-by-step Hibernate JPA capabilities tutorial to it:

    http://www.adobocode.com/spring/adding-crud-capability-to-spring-mvc

    hope it will help people!

Leave a comment