Generic DAO

Sometimes we, as a developers, need to deal with huge applications with hundreds of classes with a lot of methods inside. It is very common sometimes, when developers have time (it should be always mandatory), they try to do some code refactoring trying to improve the code quality: removing duplicated methods, renaming methods and variables to something with more sense, splitting complex methods…

Today, I am going to focus this post in the persistence layer. Sometimes, when I take a look to the DAOs in an application, all of them have the same methods that are written again and again, these methods usually are:

  • findById
  • findAll
  • persist
  • update
  • delete
  • countAll

In addition, usually the annotation “@PersistenceContext” (javax.persistence package) and the variable “EntityManager” (javax.persistence package) are defined over and over in all the DAOs. In fact, there are some DAOs that only have these methods. In this situation, sometimes is a good idea to create a generic DAO with all this stuff, avoiding in this way to repeat the same code in all the DAOs and only adding new methods to the DAOs when it is needed. Let’s see how we can do that in a easy way.

First, we need to define the interface of our generic DAO:

public interface GenericDAO<T, ID extends Serializable> {
    void persist(T entity);
    void update(T entity);
    void delete(T entity);
	T findById(ID id);
    List<T> findAll();
    Long countAll();
}

As you can see, it is quite simple. We are creating an interface but, in this case, using Generics notation we are going to allow to define the type of the object and the type of the object identifier later.

The second step, it is to create a class that implements this interface with the code for these methods. In addition, we are going to create this class as an abstract class just in case we want to add some methods without implementation or allowing easily to rewrite our defined methods in specific situations. The class is going to be as much simple as possible: no error handling, no data validation… only the implementation.

public abstract class GenericImplDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {

    @PersistenceContext
    protected EntityManager em;
	
    private Class<T> persistentClass;

    @SuppressWarnings("unchecked")
    public JPAGenericDAO() {
        this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    @Override
    public T findById(ID id) {
        return em.find(getPersistentClass(), id);
    }

    @Override
    public List<T> findAll() {
        TypedQuery<T> query = em.createQuery("from " + persistentClass.getName(), persistentClass);
        return query.getResultList();
    }

    @Override
    public Long countAll() {
        StringBuilder sb = new StringBuilder();
        sb.append("select count(E) from ");
        sb.append(persistentClass.getName());
        sb.append(" E");

        TypedQuery<Long> query = em.createQuery(sb.toString(), Long.class);
        return query.getSingleResult();
    }

    @Override
    public void persist(T entity) {
        em.persist(entity);
    }

    @Override
    public void update(T entity) {
        em.merge(entity);
    }

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

The next step is to create the interface for our concrete DAO. In this case, for example, the PersonDAO. The class Person is an entity and is something like:

  • id: Integer
  • name: String
  • surname: String
  • email: String
public interface PersonDAO extends GenericDAO<Person, Integer> {
	Person findByEmail(String email);
}

As you can see, the DAO now is very simple due to all the common methods are defined in our generic DAO and here, we only need to add the specific methods for this DAO. Another thing that deserves our attention is that we have replaced the generics notations for the specific values that apply to this class: T -> Person and ID -> Integer.

Finally, we can implement our DAO:

public class PersonImplDAO extends GenericImplDAO<Person, Integer> implements PersonDAO {

	@Override
	public Person findByEmail(String email) {
		TypedQuery<Person> query = em.createQuery("select P from Person P where P.email = :email", Person.class);
		query.setParameter("email", email);
		
		return query.getSingleResult();
	}

And this is all. Now we can do the same with all our DAOs been sure that all of them are going to have the basic methods implemented. As you can see, we have create the EntityManager as a protected variable. Doing this, we are allowed to use it in our specific DAOs. Another approach is to create the variable with private visibility and to create the getter and setter to make it accessible.

See you.

Generic DAO