Sunday, January 25, 2015

Creating Custom Generator class in Hibernate

In this post, we are going to learn how to create custom generator class in hibernate.

Hibernate supports many built in generator classes like assigned, sequence, increment, identity, native etc. But some requirements these generator classes we can't use. For example while creating new Employee record, i want to insert employee id is Emp00001, Emp00002, etc like that. There is no built in generator classes support this type of primary key generated value. So we need to go for Custom generator classes.

In order to create our own generator class, we need to implement with the org.hibernate.id.IdentifierGenerator interface. This interface is having one method. So this method we need override.

package com.varasofttech.generator;

import org.hibernate.id.IdentifierGenerator;

public class MyGenerator implements IdentifierGenerator
{
@Override
public Serializable generate(SessionImplementor session, Object object)
{
// your logic comes here.
}

}

Tools & Technologies used in this article:
  1. JDK 1.6 or above
  2. Hibernate 4.3.6
  3. HSQL DB
  4. Eclipse Luna
Required Libraries:
  • antlr-2.7.7.jar
  • dom4j-1.6.1.jar
  • hibernate-commons-annotations-4.0.5.Final.jar
  • hibernate-core-4.3.6.Final.jar
  • hibernate-jpa-2.1-api-1.0.0.Final.jar
  • jandex-1.1.0.Final.jar
  • javassist-3.18.1-GA.jar
  • jboss-logging-3.1.3.GA.jar
  • jboss-logging-annotations-1.2.0.Beta1.jar
  • jboss-transaction-api_1.2_spec-1.0.0.Final.jar
  • hsqldb-2.2.8.jar
Project Structure:

Step1: Creating the POJO or Model class: Employee.java
package com.varasofttech.pojo;

import java.io.Serializable;

/**
* @author Ranga Reddy
* @date Jan 25, 2015
* @version 1.0
* @description : Employee.java
*/


public class Employee implements Serializable {

private static final long serialVersionUID = -9001198124094210159L;

private String id; // identifier
private String name;
private int age;
private float salary;

// setters and getters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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 float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}

@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", age=" + age
+ ", salary=" + salary + "]";
}
}


Step2: Creating the Custom Generated Class: EmployeeNumberGenerator.java
package com.varasofttech.id;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;

/**
* @author Ranga Reddy
* @date Jan 25, 2015
* @version 1.0
* @description : EmployeeNumberGenerator.java
*/


public class EmployeeNumberGenerator implements IdentifierGenerator {

private String DEFAULT_SEQUENCE_NAME = "hibernate_sequence";

@Override
public Serializable generate(SessionImplementor sessionImpl, Object data)
throws HibernateException {
Serializable result = null;
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
String prefix = "Emp";
connection = sessionImpl.connection();
statement = connection.createStatement();
try {
resultSet = statement.executeQuery("call next value for "+DEFAULT_SEQUENCE_NAME);
             } catch(Exception ex) {
// if sequence is not found then creating the sequence
statement = connection.createStatement();
statement.execute("CREATE SEQUENCE "+DEFAULT_SEQUENCE_NAME);
System.out.println("Sequece Created successfully. ");
resultSet = statement.executeQuery("call next value for "+DEFAULT_SEQUENCE_NAME);
}

if(resultSet.next()) {
int nextValue = resultSet.getInt(1);
String suffix = String.format("%05d", nextValue + 1);
result = prefix.concat(suffix);
System.out.println("Custom generated Sequence value : "+result);
}
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
}

Note: Getting the next value of Sequence value in different database is

Oracle: "SELECT "+sequenceName+".NEXTVAL FROM DUAL"
PostgreSQL: "SELECT  NEXTVAL('+sequenceName+"')  

Step3: Creating the Mapping File : employee.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="com.varasofttech.pojo.Employee" table="employees">
<id name="id" column="employeeId">
<generator class="com.varasofttech.id.EmployeeNumberGenerator"/>
</id>
<property name="name" column="e_name"></property>
<property name="age" column="e_age" />
<property name="salary" column="e_salary" />
</class>
</hibernate-mapping>

Step4: Creating the Configuration file : hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>

<!-- Database Settings -->
<property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="hibernate.connection.url">jdbc:hsqldb:varasoftech</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"></property>

<!-- Dialect class -->
<property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>

<!-- Hibernate specific -->
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="hibernate.format_sql">true</property>

<mapping resource="Employee.hbm.xml"></mapping>

</session-factory>
</hibernate-configuration>

Step5: Creating the Hibernate Utility class : HibernateUtil.java
package com.varasofttech.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
/**
* @author Ranga Reddy
* @date Jan 25, 2015
* @version 1.0
* @description : HibernateUtil.java
*/

public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();

private static SessionFactory buildSessionFactory() {
try {

// Create the SessionFactory from hibernate.cfg.xml
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");

ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build();

return configuration.buildSessionFactory(serviceRegistry);

} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}

public static void closeSessionFactory() {
if(sessionFactory != null) {
sessionFactory.close();
}
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}


Step6: Creating the Client Application class : Application.java
package com.varasofttech.client;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.varasofttech.pojo.Employee;
import com.varasofttech.util.HibernateUtil;

/**
* @author Ranga Reddy
* @date Jan 25, 2015
* @version 1.0
* @description : Application.java
*/


public class Application {
public static void main(String[] args) {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

Employee employe = new Employee();
employe.setName("Ranga");
employe.setAge(27);
employe.setSalary(22000000);

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(employe);
transaction.commit();
session.close();

System.out.println("Employee Information : " +employe);
sessionFactory.close();
}
}


Output:
Custom generated Sequence value : Emp00001
Employee Information : Employee [id=Emp00001, name=Ranga, age=27, salary=2.2E7]

Happy Coding!!!

1 comments: