Spring ORM: Integrating with Hibernate framework + annotated POJO class for Hibernate mapping

In this article, we will convert the same example used earlier with fully annotated classes i.e.; annotated POJO class for Hibernate mapping between java property and database columns and deleting previously configured hibernate mapping in the spring application context

Deleting hibernate mapping files and annotating POJO classes reduces the developer work & easy maintenance and understanding

Technology Used

  • Java 1.7
  • Eclipse Luna IDE
  • Spring-4.0.0-RELEASE
  • Hibernate-4.2.2.Final
  • Apache-Maven-3.2.1
  • MySql-Connector-Java-5.1.31

Mavenize or download required jars

Add Spring-4.0.0 & mysql-connector-java dependencies to the pom.xml

<dependencies>
		<!-- Spring Core and Context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Spring ORM -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Hibernate Core -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
			<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-ehcache</artifactId>
			<version>4.3.0.Beta3</version>
		</dependency>

		<!-- MySql-Connector -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.31</version>
		</dependency>
</dependencies>

Folks who aren’t familiar with Maven concepts or don’t require maven for their project, can download the below jars individually from the spring site and include them in the classpath

  • spring-core-4.0.0-RELEASE
  • spring-context-4.0.0-RELEASE
  • spring-beans-4.0.0-RELEASE
  • spring-aop-4.0.0-RELEASE
  • spring-expression-4.0.0-RELEASE
  • spring-tx-4.0.0-RELEASE
  • spring-jdbc-4.0.0-RELEASE
  • spring-orm-4.0.0-RELEASE
  • hibernate-core- 4.2.2.Final
  • hibernate-jpa-2.0-api-1.0.1.Final
  • hibernate-commons-annotations-4.0.2.Final
  • hibernate-ehcache-4.3.0.Beta3
  • ehcahce-core-2.4.3
  • javaassist-3.15.0-GA
  • slf4j-api-1.6.1
  • antlr-2.7.7
  • jboss-logging-3.1.0.GA
  • dom4j-1.6.1
  • mysql-connector-java-5.1.31
  • commons-logging-1.1.1
  • aopalliance-1.0

 Project Structure (Package Explorer view in Eclipse)

3_SpringOrmHibernate_Project_Structure_In_Eclipse

Jars Libraries Used in the Project (Maven Dependencies)

2_SpringOrmHibernate_Jars_In_Classpath

Creating tables and inserting few records

Create table command

CREATE TABLE `PLAYER` (
  `PLAYER_ID` INT(6) NOT NULL AUTO_INCREMENT,
  `NAME` VARCHAR(50) NOT NULL,
  `AGE` INT(3) NOT NULL,
  `MATCHES` INT(3) NOT NULL,
  PRIMARY KEY (`PLAYER_ID`)
);

Insert command

INSERT INTO `PLAYER`(`NAME`, `AGE`, `MATCHES`) VALUES ("Sachin Tendulkar",41,200);
INSERT INTO `PLAYER`(`NAME`, `AGE`, `MATCHES`) VALUES ("Shane Warne",44,145);
INSERT INTO `PLAYER`(`NAME`, `AGE`, `MATCHES`) VALUES ("Kevin Pietersen",34,104);
INSERT INTO `PLAYER`(`NAME`, `AGE`, `MATCHES`) VALUES ("Shahid Afridi",35,27);
INSERT INTO `PLAYER`(`NAME`, `AGE`, `MATCHES`) VALUES ("Brian Lara",45,131);
INSERT INTO `PLAYER`(`NAME`, `AGE`, `MATCHES`) VALUES ("Graeme Smith",34,117);
INSERT INTO `PLAYER`(`NAME`, `AGE`, `MATCHES`) VALUES ("Mahela Jayawardene",37,145);

Spring Configuration Context xml

This Spring Bean xml defines

  • dataSource with value for driverClassName, url, username and password
  • sessionFactory bean which injects three properties for this example namely dataSource, annotatedClasses and hibernateProperties
  • <context:annotation-config /> – to activate beans registered with the application context
  • <context:component-scan base-package=“”/> – scans package to find & register beans within the application context
  • transactionManager  to handle/support spring managed transaction
  • <tx:annotation-driven /> to activate annotation-based spring transaction support
  • annotatedClasses describes the fully qualified package name of the Hibernate annotated POJO class
  • hibernateProperties describes hibernate properties like which SQL dialect to use, whether table should be auto created and whether to show or not executing SQL queries in hibernate

Note: Purposely kept mappingResources element commented to show that either one of them can be used for Hibernate mapping between java property and database columns

ApplicationContext.xml

<?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" 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/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

	<!-- to activate annotations in beans already registered in the application context -->
	<context:annotation-config />

	<!-- scans packages to find and register beans within the application context -->
	<context:component-scan base-package="com.spring.series.orm.dao.impl" />

	<!-- turn on spring transaction annotation -->
	<tx:annotation-driven transaction-manager="transactionManager" />

	<!-- Transaction Manager -->
	<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>

	<!-- Session Factory -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<!-- <property name="mappingResources">
			<list>
				<value>com/spring/series/orm/hbm/Player.hbm.xml</value>
			</list>
		</property> -->
		<property name="annotatedClasses">
			<list>
				<value>com.spring.series.orm.model.Player</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<prop key="hibernate.show_sql">true</prop>
			</props>
		</property>
	</bean>

	<!-- dataSource configuration -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/benchresources" />
		<property name="username" value="root" />
		<property name="password" value="" />
	</bean>
</beans>

Let’s see coding in action

 

Model class Player with four primitive attributes with their getter/setter && no-arg constructor, 3-arg constructor and 4-arg constructor
Also the Hibernate POJO class is annotated describing the mapping between java property and database columns

@Entity:  represents an object that can be persisted in the database and for this class should have no-arg constructor
@Table: describes which table in the database to map with this class (properties)
@Id: defines unique value, which means it represents primary key in the database table
@GeneratedValue: this will be taken care by hibernate to define generator sequence
@Column: tells to map this particular property to table column in the database

For example, “age” property used to map “AGE” column in the “PLAYER” table in the database

@Column(name= “AGE”)
private int age;

Note: we can add attributes to the @Column annotation like name, length, nullable and unique

Player.java

package com.spring.series.orm.model;

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

@Entity
@Table(name = "PLAYER")
public class Player {

	// member variables
	@Id
	@GeneratedValue
	@Column(name = "PLAYER_ID")
	private int playerId;

	@Column(name= "NAME")
	private String name;

	@Column(name= "AGE")
	private int age;

	@Column(name= "MATCHES")
	private int matches;

	// default constructor
	public Player() {
		super();
	}

	// 3-arg parameterized-constructor
	public Player(String name, int age, int matches) {
		super();
		this.name = name;
		this.age = age;
		this.matches = matches;
	}

	// 4-arg parameterized-constructor
	public Player(int playerId, String name, int age, int matches) {
		super();
		this.playerId = playerId;
		this.name = name;
		this.age = age;
		this.matches = matches;
	}

	// getter and setter
	public int getPlayerId() {
		return playerId;
	}
	public void setPlayerId(int playerId) {
		this.playerId = playerId;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public int getMatches() {
		return matches;
	}
	public void setMatches(int matches) {
		this.matches = matches;
	}
}

PlayerDAO interface
PlayerDAO interface with CRUD operation to interact with database

  • create or save new player information into the database
  • get player based on the PLAYER_ID
  • update player information taking player object as input argument
  • delete player information from the database with playerId as formal argument
  • get all players stored in the database from PLAYER table

 Note: It is always good programming practice to write code-to-interface

PlayerDAO.java

package com.spring.series.jdbc.dao;

import java.util.List;

import com.spring.series.jdbc.model.Player;

public interface PlayerDAO {

	// simple CRUD operations
	public String createOrSaveNewPLayer(Player player);
	public Player getPlayer(int playerId);
	public String updatePlayerInfo(Player player);
	public String deletePlayerInfo(String playerId);
	public List<Player> getAllPlayer();
}

PlayerDAOImpl class

This Impl class implements above interface which exposes CRUD like operations
It uses Hibernate’s sessionFactory configured in the ApplicationContext.xml file to interact with MySql database to do database operations

CRUD operation uses readily available Hibernate API and in this way database interaction becomes simpler and faster yielding in better performance

@Transaction: this is annotated on top of the every methods of this class to inform spring container to handle/manage transaction.

Note: Spring has stopped support for HibernateTemplate and DaoSupport classes from Hibernate 4 support packages. Still using this can throw error

java.lang.NoSuchMethodError: org.hibernate.SessionFactory.openSession()Lorg/hibernate/classic/Session

Instead use core Hibernate classes like sessionFactory directly in the Spring integrated application. See here for information

PlayerDAOImpl.java

package com.spring.series.orm.dao.impl;

import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.spring.series.orm.dao.PlayerDAO;
import com.spring.series.orm.model.Player;

@Repository("playerDAO")
public class PlayerDAOImpl implements PlayerDAO {

	@Autowired
	private SessionFactory sessionFactory;

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	/**
	 * create or inserts the new player information into the database using simpleJdbcTemplate
	 */
	@Transactional
	public String createOrSaveNewPLayer(Player player) {

		int playerId = (Integer) getSessionFactory().getCurrentSession().save(player);
		return "Player information saved successfully with PLAYER_ID " + playerId;
	}

	/**
	 * This method retrieves a player from database using jdbcTemplate based on the PLAYER_ID supplied in the formal arguments
	 */
	@Transactional
	public Player getPlayer(int playerId) {

		Player player = (Player) getSessionFactory().getCurrentSession().get(Player.class, playerId);
		return player;
	}

	/**
	 * This method updates the player information in the database using simpleJdbcTemplate
	 */
	@Transactional
	public String updatePlayerInfo(Player player) {

		getSessionFactory().getCurrentSession().update(player);
		return "Player information updated successfully";
	}

	/**
	 * This method deletes the player information from the database using simpleJdbcTemplate
	 */
	@Transactional
	public String deletePlayerInfo(Player player) {

		getSessionFactory().getCurrentSession().delete(player);
		return "Player information deleted successfully";
	}

	/**
	 * Retrieves all players from the database using simpleJdbcTemplate
	 */
	@Transactional
	public List<Player> getAllPlayer() {

		return sessionFactory.getCurrentSession().createCriteria(Player.class).list();
	}
}

Time to Test !!

TestPlayerInfo class

This class is used to test the above Spring + Hibernate Integration implementation

TestPlayerInfo.java

package com.spring.series.orm;

import java.util.List;

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

import com.spring.series.orm.dao.PlayerDAO;
import com.spring.series.orm.model.Player;

public class TestPlayerInfo {

	public static void main(String[] args) {
		testSpringOrmHibernateIntegration();
	}

	/**
	 * Test method : invokes all public DAO methods using Spring Dependency Injection after loading the context xml file
	 */
	private static void testSpringOrmHibernateIntegration(){

		// loads the context xml and uses getBean() to retrieve the bean
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/spring/series/orm/ApplicationContext.xml");
		PlayerDAO playerDAO = (PlayerDAO) applicationContext.getBean("playerDAO");

		System.out.println("\nSpring + Hibernate Integration");

		// invokes createOrSaveNewPLayer() method
		System.out.println("\nA. Invkoing createOrSaveNewPLayer() method to create/save new player information");
		Player newPlayer = new Player("Steve Waugh", 49, 168);
		String strCreateOrSave = playerDAO.createOrSaveNewPLayer(newPlayer);
		System.out.println("Return message : " + strCreateOrSave);

		// invokes getPlayer() method
		System.out.println("\nB. Invkoing getPlayer() method to retrieve player based on the player_id supplied in the formal argument");
		Player player5 = playerDAO.getPlayer(5);
		System.out.println("ID\tName\t\t\tAge\tMatches");
		System.out.println("==\t================\t===\t=======");
		System.out.println(player5.getPlayerId() + "\t" + player5.getName() + "\t" + player5.getAge() + "\t" + player5.getMatches());

		// invokes updatePlayerInfo() method
		System.out.println("\nC. Invkoing updatePlayerInfo() method to update Player information");
		Player updatePlayer = new Player(3, "Kevin Pietersen", 35, 104);
		String strUpdate = playerDAO.updatePlayerInfo(updatePlayer);
		System.out.println("Return message : " + strUpdate);

		// invokes deletePlayerInfo() method
		System.out.println("\nD. Invkoing deletePlayerInfo() method to delete player inforamtion from the database");
		Player deletePlayer = new Player(6, "Graeme Smith", 34, 117);
		String strDelete = playerDAO.deletePlayerInfo(deletePlayer);
		System.out.println("Return message : " + strDelete);

		// invokes getAllPlayer() method
		System.out.println("\nE. Invkoing getAllPlayer() method to retrieve all players from the database");
                List<Player> lstPlayer = playerDAO.getAllPlayer();
		System.out.println("ID\tName\t\t\tAge\tMatches");
		System.out.println("==\t================\t===\t=======");
		for(Player player : lstPlayer){
			System.out.println(player.getPlayerId() + "\t" + player.getName() + "\t" + player.getAge() + "\t" + player.getMatches());
		}
	}
}

Output in console:

Aug 06, 2014 11:14:06 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1acb189: startup date [Wed Aug 06 23:14:06 IST 2014]; root of context hierarchy
Aug 06, 2014 11:14:06 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [com/spring/series/orm/ApplicationContext.xml]
Aug 06, 2014 11:14:07 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
Aug 06, 2014 11:14:07 PM org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.2.Final}
Aug 06, 2014 11:14:07 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.2.2.Final}
Aug 06, 2014 11:14:07 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Aug 06, 2014 11:14:07 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Aug 06, 2014 11:14:07 PM org.hibernate.internal.util.xml.DTDEntityResolver resolveEntity
WARN: HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
Aug 06, 2014 11:14:07 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
Aug 06, 2014 11:14:07 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
Aug 06, 2014 11:14:08 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Aug 06, 2014 11:14:08 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000228: Running hbm2ddl schema update
Aug 06, 2014 11:14:08 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000102: Fetching database metadata
Aug 06, 2014 11:14:08 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000396: Updating schema
Aug 06, 2014 11:14:08 PM org.hibernate.tool.hbm2ddl.TableMetadata <init>
INFO: HHH000261: Table found: benchresources.player
Aug 06, 2014 11:14:08 PM org.hibernate.tool.hbm2ddl.TableMetadata <init>
INFO: HHH000037: Columns: [matches, name, age, player_id]
Aug 06, 2014 11:14:08 PM org.hibernate.tool.hbm2ddl.TableMetadata <init>
INFO: HHH000108: Foreign keys: []
Aug 06, 2014 11:14:08 PM org.hibernate.tool.hbm2ddl.TableMetadata <init>
INFO: HHH000126: Indexes: [primary]
Aug 06, 2014 11:14:08 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000232: Schema update complete
Aug 06, 2014 11:14:08 PM org.springframework.orm.hibernate4.HibernateTransactionManager afterPropertiesSet
INFO: Using DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource@1c51b0e] of Hibernate SessionFactory for HibernateTransactionManager

Spring + Hibernate Integration

A. Invkoing createOrSaveNewPLayer() method to create/save new player information
Hibernate: insert into PLAYER (NAME, AGE, MATCHES) values (?, ?, ?)

Return message : Player information saved successfully with PLAYER_ID 8

B. Invkoing getPlayer() method to retrieve player based on the player_id supplied in the formal argument
Hibernate: select player0_.PLAYER_ID as PLAYER1_0_0_, player0_.NAME as NAME2_0_0_, player0_.AGE as AGE3_0_0_, player0_.MATCHES as MATCHES4_0_0_ from PLAYER player0_ where player0_.PLAYER_ID=?

ID	Name			Age	Matches
==	================	===	=======
5	Brian Lara		45	131

C. Invkoing updatePlayerInfo() method to update Player information
Hibernate: update PLAYER set NAME=?, AGE=?, MATCHES=? where PLAYER_ID=?

Return message : Player information updated successfully

D. Invkoing deletePlayerInfo() method to delete player inforamtion from the database
Hibernate: delete from PLAYER where PLAYER_ID=?

Return message : Player information deleted successfully

E. Invkoing getAllPlayer() method to retrieve all players from the database
Hibernate: select this_.PLAYER_ID as PLAYER1_0_0_, this_.NAME as NAME2_0_0_, this_.AGE as AGE3_0_0_, this_.MATCHES as MATCHES4_0_0_ from PLAYER this_

ID	Name			Age	Matches
==	================	===	=======

1	Sachin Tendulkar	41	200
2	Shane Warne		44	145
3	Kevin Pietersen	        35	104
4	Shahid Afridi		35	27
5	Brian Lara		45	131
7	Mahela Jayawardene	37	145
8	Steve Waugh		49	168

Conclusion: With full annotated hibernate classes, maintenance and readability of the project improves

Download project

Spring-ORM-Integrating-with-Hibernate-framework-annotated-POJO (7kB)

 

Read Also:

 

Happy Coding !!
Happy Learning !!

Spring ORM: Integrating with Hibernate framework using annotation