DAO layer – Generics to the rescue
Unfortunately I feel the main stream developers still afraid of it.
However, in analogy to Hagrid’s spiders I would say that Generics are seriously misunderstood creatures… :-)
I hope the following example will demonstrate how useful they can be.
The Problem – DAO (Data Access Objects) classes have common methods such as save, update, delete, loadAll.. which are required in every DAO class.
Writing a base class with these common methods and making every DAO object extend it, is simply not enough since each DAO class represents a different domain class and therefore the type used in the common methods’ signature is different (although implementation is similar), for example:
class OrderDAO { //save method receive an Order public void save(Order order){....} //getAll method return Orders List public List<Order> getAll(){...} } class UserDAO{ //save method receive an User public void save(User user){....} //getAll method return Users List public List<User> getAll(){...} }
How Generics can help us create a base class with a common implementation and yet, keep method signature type-safety?
First, we need to define an interface with the common methods:
/** * Base interface for CRUD operations and common queries */ public interface IDaoBase<T> { public List<T> loadAll(); public void save(T domain); public void update(T domain); public void delete(T domain); public T get(Serializable id); /** * Get list by criteria * @param detachedCriteria the domain query criteria, include condition and the orders. * @return * */ public List<T> getListByCriteria(DetachedCriteria detachedCriteria); public List<T> getListByCriteria(DetachedCriteria detachedCriteria, int offset, int size); }
Please note that we utilize generics so each method signature has a type T, which in the implemented DAO classes, will be a concrete type, per domain.
The second step is to create an abstract class which implements the common functionality:
public abstract class DaoBase<T> extends HibernateDaoSupport implements IDaoBase<T> { private Class<T> entityClass; @Autowired public void setSession(SessionFactory sessionFactory){ this.setSessionFactory(sessionFactory); } public DaoBase() { entityClass = (Class<T>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; } public List<T> loadAll(){ return getHibernateTemplate().loadAll(entityClass); } public void delete(T domain) { getHibernateTemplate().delete(domain); } public void save(T domain) { getHibernateTemplate().saveOrUpdate(domain); } public void update(T domain) { getHibernateTemplate().merge(domain); } public T get(Serializable id) { T o = (T) getHibernateTemplate().get(entityClass, id); return o; } public List<T> getListByCriteria(DetachedCriteria detachedCriteria, int offset, int size) { return getHibernateTemplate().findByCriteria(detachedCriteria, offset, size); } public List<T> getListByCriteria(DetachedCriteria detachedCriteria) { return getHibernateTemplate().findByCriteria(detachedCriteria); } }
And that’s it !
Take a minute or two to inspect how the base object implements a generic functionality with a type-safety manner.
All we have to do when implementing a new DAO is:
1. Interface to extend the IDaoBase with a concrete type
public interface DaoUser extends IDaoBase<User> {//<=Notice the User typing //Add any additional custom methods.. public User getbyUsername(String username); public User getbyEmail(String email); }
2. Implementation to extend the DaoBase with a concrete type
//This class has all the common methods, which are type safe for the User class @Repository("daoUser") public class DaoUserImpl extends DaoBase<User> implements DaoUser { //<=Notice the User typing public User getbyUsername(String username) { // concrete implmentation ... }
So now you see how powerful it is to use generics. Hope it is now a bit less scary and more understood…
Reference: DAO layer – Generics to the rescue from our JCG partner Gal Levinsky at the Gal Levinsky’s blog blog.