Implementing Hibernate DAOs

Christian Bauer at the Hibernate team blog has written an improved version of the DAOs of the Caveat Emptor application of the Hibernate in Action book. This new versions will probably be included in the second edition of the book. The new DAOs are implemented in Java 5 using generics and other Java 5 features. Christian Bauer has created a common abstract DAO class, the GenericHibernateDAO, that makes implementing new DAOs easier and removes the code duplication found in the previous versions of the DAOs. I believe that if you plan to use Hibernate with Java 5 you should read his post since it provides a very good starting point for implementing DAOs with generics.

If you are using Hibernate in Java 2 and you want to reuse code from the current version of the CaveatEmptor application you can make a small refactoring to the DAO classes and introduce a common abstract DAO class that will make implementing DAOs easier and will remove much of the duplicate code found in the current implementation of the DAOs.

This refactoring is based on the observation that a lot of the Hibernate operations take the java.lang.Class object of the mapped class as an argument. By introducing a java.lang.Class field (mappedClass) in an abstract DAO class (AbstractDAO) we can move there all the operations of the concrete DAOs of theCaveat Emptor application. With this refactoring of course we assume that we will have a one-to-one mapping between our mapped classes and our DAO classes.

Below I have listed a possible implementation of the abstract DAO and also an implementation of the UserDAO so you can see the code that is removed from the concrete DAOs. The below code is heavily based on the original implementation of Christian Bauer.

// The below code is based on the DAO implementation of
// the Caveat Emptor application of the Hibernate project
// see: http://caveatemptor.hibernate.org
import java.io.Serializable;
import java.util.Collection;

import net.sf.hibernate.Criteria;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.LockMode;
import net.sf.hibernate.Session;
import net.sf.hibernate.expression.Example;

import org.hibernate.auction.exceptions.InfrastructureException;
import org.hibernate.auction.persistence.HibernateUtil;

public class AbstractDAO {

  private Class mappedClass;

  public AbstractDAO(Class c) {
    mappedClass = c;
    HibernateUtil.beginTransaction();
  }

  protected Object getById(Long id, boolean lock) throws InfrastructureException {
    Session session = HibernateUtil.getSession();
    Object object = null;
    try {
      if (lock) {
        object = session.load(mappedClass, id, LockMode.UPGRADE);
      } else {
        object = session.load(mappedClass, id);
      }
    }  catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
    return object;
  }

  public Collection findAll() throws InfrastructureException {
    Collection objects;
    try {
      objects = HibernateUtil.getSession().createCriteria(mappedClass).list();
    } catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
    return objects;
  }

  public Collection findByExample(Object example) throws InfrastructureException {
    Collection users;
    try {
      Criteria crit = HibernateUtil.getSession().createCriteria(mappedClass);
      users = crit.add(Example.create(example)).list();
    } catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
    return users;
  }

  public void makePersistent(Object o) throws InfrastructureException {
    try {
      HibernateUtil.getSession().saveOrUpdate(o);
    } catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
  }

  public void makeTransient(Object o) throws InfrastructureException {
    try {
      HibernateUtil.getSession().delete(o);
    } catch (HibernateException ex) {
      throw new InfrastructureException(ex);
    }
  }

  public Class getMappedClass() {
    return mappedClass;
  }
}


import org.hibernate.auction.exceptions.InfrastructureException;
import org.hibernate.auction.model.User;

public class UserDAO extends AbstractDAO {

  public UserDAO() {
    // Pass the class of the DAO to the parent
    super(User.class);
  }

  // Provide a type safe way to get a User object
  // without a cast from the user of the api.
  public User getUserById(Long id, boolean lock) throws InfrastructureException {
    return (User) getById(id, lock);
  }
}