Hibernate GenericDao

Need for GenericDao

When we use hibernate in a typical J2EE project, there are some basic operations which must be supported on all hibernate entities. These operations are create, update, delete, find, findAll entities.  A generic code can be written which performs these basic operations for the all entities. This approach has following advantages

  • Generic code allows in removing the code duplication. It will save lot of time spent in writing/testing duplicate code.
  • It ensures the consistent interface. Consistent interface helps developer understand and implement code much faster

Sometimes the second point consistent interface does not seem too much of value, but I have seen projects where the interface was not consistent and due to which developer spent hours and hours of time just to understand the code and implement the things which were redundant.

 

How to write GenericDao

GenericDao needs to be written using Generics, so that it can support any hibernate entity. There is an interface GenericDao and it’s implementation GenericDaoImpl. All the Dao interface should extend the GenericDao interface and all the dao implementation should extend the GenerficDaoImpl implementation.

package in.pm.hibernate.genericdao_example.dao;

import java.io.Serializable;
import java.util.List;

public interface GenericDao<T, PK extends Serializable> {

    public PK create(T object);
    
    public T find(PK primaryKey);
    
    public List<T> finalAll();
    
    public void update(T object);
    
    public void delete(T object);
}

Following is the implementation for GenericDao. Here hibernate is configured directly with Spring and no JPA is used. But if we want to use the JPA then also the approach remains the same. We get the actual type of class by looking at the type argument of the generic class.

package in.pm.hibernate.genericdao_example.dao.impl;

import in.pm.hibernate.genericdao_example.dao.GenericDao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

public class GenericDaoImpl<T, PK extends Serializable> implements
        GenericDao<T, PK> {

    private Class<T> actualType;

    @Autowired
    private SessionFactory sessionFactory;

    @SuppressWarnings("unchecked")
    public GenericDaoImpl() {

        // get superclass declaration
        ParameterizedType genericSuperClass = (ParameterizedType) getClass()
                .getGenericSuperclass();
        // Find out the actual type
        this.actualType = (Class<T>) genericSuperClass.getActualTypeArguments()[0];

    }

    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    @Transactional
    public PK create(T object) {
        PK id = (PK) getSession().save(object);
        return id;
    }

    public T find(PK primaryKey) {
        T object = getSession().get(actualType, primaryKey);
        return object;
    }

    @SuppressWarnings("unchecked")
    public List<T> finalAll() {
        String findAllQueryStr = "from " + actualType.getName();
        Query findAllQuery = getSession().createQuery(findAllQueryStr);
        List<T> objects = (List<T>) findAllQuery.list();
        return objects;
    }

    public void update(T object) {
        getSession().update(object);
    }

    public void delete(T object) {
        getSession().delete(object);
    }

}

 

Usage of GenericDao

We will take two entities (Device, User) and try to see how GenericDao is useful in doing db operations for these two entities.

package in.pm.hibernate.genericdao_example.entity;

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

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "Device")
public class Device {

    @Id
    @GeneratedValue(generator="increment")
    @GenericGenerator(name= "increment", strategy="increment")
    private Long id;
    
    private String deviceName;
    
    private String deviceType;

    
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getDeviceName() {
        return deviceName;
    }

    public void setDeviceName(String deviceName) {
        this.deviceName = deviceName;
    }

    public String getDeviceType() {
        return deviceType;
    }

    public void setDeviceType(String deviceType) {
        this.deviceType = deviceType;
    }
    
     
}

 

package in.pm.hibernate.genericdao_example.entity;

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 {

    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    private Long id;

    private String firstName;
    private String lastName;
    private String email;
    
    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    
    
}

 

Dao for Entity

For each entity Dao class needs to be created which will be responsible for doing basic CRUD operation on entity and will support additional query if required.

Dao Interfaces

package in.pm.hibernate.genericdao_example.dao;

import in.pm.hibernate.genericdao_example.entity.Device;

public interface DeviceDao extends GenericDao<Device, Long>{

}
package in.pm.hibernate.genericdao_example.dao;

import in.pm.hibernate.genericdao_example.entity.User;

public interface UserDao extends GenericDao<User, Long> {
    
    public User getUserByName(String firstName);
}

 

Dao Implementation

package in.pm.hibernate.genericdao_example.dao.impl;

import org.springframework.stereotype.Repository;

import in.pm.hibernate.genericdao_example.dao.DeviceDao;
import in.pm.hibernate.genericdao_example.entity.Device;

@Repository
public class DeviceDaoImpl extends GenericDaoImpl<Device, Long> implements DeviceDao{

}
package in.pm.hibernate.genericdao_example.dao.impl;

import org.hibernate.Query;
import org.springframework.stereotype.Repository;

import in.pm.hibernate.genericdao_example.dao.UserDao;
import in.pm.hibernate.genericdao_example.entity.User;

@Repository
public class UserDaoImpl extends GenericDaoImpl<User, Long> implements UserDao{

    public User getUserByName(String firstName) {
        String userByName = "from User where user.firstName = :firstName ";
        Query userByNameQuery = getSession().createQuery(userByName);
        userByNameQuery.setString("firstName", firstName);
        return (User)userByNameQuery.uniqueResult();
    }
    
}

 

As we can see that since we have used generic dao, methods (create, update, delete, find and findAll)  are automatically inherited by both dao (DeviceDao and UserDao).  UserDao had additional requirement for finding user according to its name, so only that method is implemented in the UserDao.

This has ensured code is reused and consistent interface. For e.g. if we want to store any entity, we just have to call create method of that entity’s dao. Similar is the case for update, delete, find and findAll.

 

Test Application

Below is the test class which was used for testing. It creates two entity (User and Device) and inserts it into database.

package in.pm.hibernate.genericdao_example.app;

import in.pm.hibernate.genericdao_example.dao.DeviceDao;
import in.pm.hibernate.genericdao_example.dao.UserDao;
import in.pm.hibernate.genericdao_example.entity.Device;
import in.pm.hibernate.genericdao_example.entity.User;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    
    @SuppressWarnings("resource")
    public static void main(String[] args) {
        
        ApplicationContext context = 
                new AnnotationConfigApplicationContext(AppConfiguration.class);
        
        UserDao userDao = context.getBean(UserDao.class);
        DeviceDao deviceDao = context.getBean(DeviceDao.class);
        
        User user = new User();
        user.setFirstName("Pranav");
        user.setLastName("Maniar");
        user.setEmail("pranav9428@gmail.com");
        
        Device device = new Device();
        device.setDeviceName("Moto G");
        device.setDeviceType("Mobile");
        
        userDao.create(user);
        deviceDao.create(device);
        
    }

}

 

Leave a Reply