Hibernate DAO using Java 5 Generics

For one of my projects, I have used Java 5 Generics to simplify creation of Hibernate DAO's. I no longer have to duplicate the typical CRUD operations in every DAO class. Note that I am using Spring's HibernateDaoSupport. If you want to see an example of a non-Spring generic DAO, the authors of Hibernate have posted one on their blog. Though mine may not be the best practices for Hibernate, I thought I'd post it just to show an example of what can be done with Java 5 generics and how much code can be reduced with it.

Here is my generic class:
public abstract class AbstractHibernateDAOImpl<T extends Serializable, KeyType extends Serializable>
        extends HibernateDaoSupport {

    protected Class<T> domainClass = getDomainClass();

    /**
     * Method to return the class of the domain object
     */
    protected abstract Class<T> getDomainClass();

    @SuppressWarnings("unchecked")
    public T load(KeyType id) {
        return (T) getHibernateTemplate().load(domainClass, id);
    }

    public void update(T t) {
        getHibernateTemplate().update(t);
    }

    public void save(T t) {
        getHibernateTemplate().save(t);
    }

    public void delete(T t) {
        getHibernateTemplate().delete(t);
    }

    @SuppressWarnings("unchecked")
    public List<T> getList() {
        return (getHibernateTemplate().find("from " + domainClass.getName() + " x"));
    }

    public void deleteById(KeyType id) {
        Object obj = load(id);
        getHibernateTemplate().delete(obj);
    }

    public void deleteAll() {
        getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException {
                String hqlDelete = "delete " + domainClass.getName();
                int deletedEntities = session.createQuery(hqlDelete).executeUpdate();
                return null;
            }

        });
    }

    public int count() {
        List list = getHibernateTemplate().find(
                "select count(*) from " + domainClass.getName() + " x");
        Integer count = (Integer) list.get(0);
        return count.intValue();
    }

}
I have a generic interface to go along with this class:
public interface AbstractDAO <DomainObject, KeyType> {

    public DomainObject load(KeyType id);
    
    public void update(DomainObject object);

    public void save(DomainObject object);

    public void delete(DomainObject object);
    
    public void deleteById(KeyType id);

    public List<DomainObject> getList();
    
    public void deleteAll();
    
    public int count();
	
}
And now for an example usage with a Hibernate domain object of type PageCache which has an Integer for its primary key. The interface:
public interface PageCacheDAO extends AbstractDAO<PageCache, Integer> {

}
And the implementation of that interface:
public class PageCacheDAOImpl extends AbstractHibernateDAOImpl<PageCache, Integer> implements PageCacheDAO {

    @Override
    protected Class<PageCache> getDomainClass() {
        return PageCache.class;
    }
    
}
Note that the getDomainClass() method was just to so I could get the class name for use in my Hibernate queries. There does not appear to be a way to get it from the generic class type. Maybe there is another way to do it, or maybe I could have constructed Hibernate queries differently to work around it.

Comments

getDomainClass()

You can get the domain class in the abstract class using parameterized type refelection... . Note that this code runs only for a concrete implementation, so getClass() will be returning something like PageCacheDAOImpl.class, which is why you need the call to getGenericSuperclass().

protected Class getDomainClass() {
    if (domainClass == null) {
    	ParameterizedType thisType = (ParameterizedType) getClass().getGenericSuperclass();
        domainClass = (Class) thisType.getActualTypeArguments()[0];
    }
    return domainClass;
}

Sorry for the formatting... your article uses the PRE tag, but that doesn't seem to work in comments.

Thanks for the code sample.

Thanks for the code sample. I went ahead and added the pre tags to your comment and enabled pre tags for comments as well.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.