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 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(); }
public interface PageCacheDAO extends AbstractDAO<PageCache, Integer> { }
public class PageCacheDAOImpl extends AbstractHibernateDAOImpl<PageCache, Integer> implements PageCacheDAO { @Override protected Class<PageCache> getDomainClass() { return PageCache.class; } }
Comments
DAO Fusion
Hi, we have released an OpenSource project aimed at developing Java based DAO layers.
You can find it here or here.
DAO Fusion is a lightweight yet comprehensive tool for building reliable, maintainable and testable DAO layers using JPA / Hibernate.
It covers five main areas related to DAO layer development:
The project is open to everyone interested in JPA, Hibernate and related technologies.
Cheers,
Vojtech
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().
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.
A nice code sample indeed.
A nice code sample indeed. However, it got me into trouble when using AOP and cglib. It seems cglib has a problem with the casting to a parameterized type. Just to let you know...