Friday, January 18, 2008

[Java] Generic Data Access Objects with Java Generics

The Data Access Object (DAO) pattern is an essential design pattern in enterprise applications. In a DAO all data access to the underlying data source is encapsulated by providing a generic interface. Service components use the DAO in order to load and save data to the data source.

A DAO interface usually provides common CRUD (Create, Read, Update, Delete) operations. The implementation of such DAOs can become a painful and boring work, because almost the same code is written for every DAO. Consider an application with hundreds of domain objects, where each object must provide a DAO!

In my post “Has JPA killed the DAO” I summarize the necessity of the DAO based on the discussion from Adam Bien. In this post I mentioned that JPA provides a generic data access functionality. In the present post I will show how to write a Generic DAO interface by using Java 5 Generics, Hibernate and Spring.

Java 5 Generics allows to parametrize and to create typesafe DAO interfaces. So it makes sense to adapt generics to implement a generic DAO. The following code snipped provides such a DAO interface


public interface GenericDao {

public T saveOrUpdate(T entity);

public void delete(T entity);

public T findById(ID id, boolean lock);

public List findAll();

public List findByExample(T exampleInstance);
}

The interface definition gets two parameters: T for the type of the domain object and the ID for the type of primary key. These parameters are then used in the interface methods. There are no specific domain objects but still typesafe by using Generics. Now we have an implementation with Hibernate and Spring. In this case we use HibernateDaoSupport from Spring:

public class HibernateGenericDao extends HibernateDaoSupport implements GenericDao {
private Class type;

public HibernateGenericDao(Class type){
this.type = type;
}

@Override
public T saveOrUpdate(T entity) {
getHibernateTemplate().saveOrUpdate(entity);
return entity;
}

@Override
public void delete(T entity) {
getHibernateTemplate().delete(entity);
}

@Override
public List findAll() {
return getHibernateTemplate().loadAll(type);
}

@Override
public List findByExample(T exampleInstance) {
return getHibernateTemplate().findByExample(exampleInstance);
}

@Override
public T findById(ID id, boolean lock) {
return (T)getHibernateTemplate().load(type.getClass(), id);
}
}

Also the implementation needs no specific domain objects, we still work with Generics. The type attribute in the class is important. It specifies the type of the domain object for which the DAO should work and is further injected by Spring when using Dependency injection:

Instead of using two separate DAO implementation we only have one generic DAO and instantiate the DAO for the business object. The constructor gets the type of the domain object. That makes sense, wow.

If you need domain specific DAO operations extend the Generic DAO!!

Hope this blog impresses you to take a look to Java 5 Generics and Generic DAOs.

1 comment:

Anonymous said...

generic-dao is an interesting solution: http://code.google.com/p/generic-dao