CDI Generic Dao

UPDATE(November/2014):

Just added multiple datasources support to our example application, see here details: https://rpestano.wordpress.com/2014/11/04/cdi-crud-multi-tenancy/

<END UPDATE>

UPDATE(September/2014):

I’ve revisited this post some days ago and refactored the code, of course i keeped everything here and the github repo untouched so you can folow this post. Instead i’ve created a new github repository to share the new code there, i have updated the apis, added some (arquillian)tests, new functionality like true pagination and new apis(hibernate and deltaspike) and now it works on wildfly, Glassfish and Jboss7. I’ve also changed a bit of the project structure but the idea is the same, the code can be found here: cdi-crud.

<END UPDATE>

In this post i will show how to implement basic CRUD operations using a generic dao based on CDI beans. Its not the purpose to discuss about the Dao pattern itself, there are already long discussions about it see[1],[2],[3] and [4]. For a good and detailed introduction about the pattern see [5].

The source code can be found here: https://github.com/rmpestano/cdi-generic-dao and also as usual there is a video produced by this post here: http://www.youtube.com/watch?v=9mGQx0tjxgo&feature=youtu.be

Show me the code

lets get hands dirty with some code, here is the classic BaseEntity which in this case will hold only the primary key of our JPA entities:

@MappedSuperclass
public abstract class BaseEntity<ID> {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private ID id;

    public ID getId() {
        return id;
    }

    public void setId(ID id) {
        this.id = id;
    }

}

Next is the simple Car entity:

@Entity
public class Car extends BaseEntity<Integer>{

    private String model;
    private Double price;

 //getter & setters

Now the so called generic dao:

@Stateless
@Named("baseDao")
public class<T extends BaseEntity<ID>, ID>> implements Serializable {

    @PersistenceContext
    private EntityManager entityManager;
    private Class entityClass;

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public Class getEntityClass() {
        if (entityClass == null) {
            //only works if one extends BaseDao, we will take care of it with CDI
            entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return entityClass;
    }

    public void setEntityClass(Class entityClass) {
        this.entityClass = entityClass;
    }

    //utility database methods
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public T find(ID id) {
        return (T) this.entityManager.find(getEntityClass(), id);
    }

    public void delete(ID id) {
        Object ref = this.entityManager.getReference(getEntityClass(), id);
        this.entityManager.remove(ref);
    }

    public T update(T t) {
        return (T) this.entityManager.merge(t);
    }

    public void insert(T t) {
        this.entityManager.persist(t);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public List findAll() {
        return entityManager.createQuery("Select entity FROM "+getEntityClass().getSimpleName() +" entity").getResultList();
    }
//more utility methods

It is an usual dao, it has a PersistenceContext injected by the EJB container, it’s a Stateless Session Bean, have some utility database methods but it cannot work alone, you need to feed it with an Entity so it can perform database operations.

There are several ways to provide an entity to a generic dao, via constructor, annotation, extending it etc. In this example we provide the Entity by two manners, extending it and via CDI producer.

Extending the Dao

Here is a generic dao specialization, the CarDao:

@Stateless
public class CarDao extends BaseDao<Car, Integer>{
    //put here specific car business
}

The entity is passed to BaseDao in getEntityClass() via ParameterizedType and now we can inject our dao in any bean:


public class SomeBean{
    @Inject
    CarDao carDao;

    public void createCar(Car car){
      carDao.insert(car);
    }
}

this is good cause you usually will extend the base dao to add some more complex operations then CRUD but sometimes you just need the CRUD and you will have to create empty daos extending the BaseDao just to benefit from its utility methods, what i really want is to inject the BaseDao directly:

   @Inject
   BaseDao<Car,Integer> baseCarDao;

The only thing that prohibits me from doing that is that the ParameterizedType can only be got from a superclass with getGenericSuperclass()(the only way I know 😉 ), at least before CDI came.

Producing the Dao

We are going to set the entity in a CDI producer, to do that we provide a qualifier that will tell CDI we want a produced Dao not the real one, here is the Dao qualifier:

@Qualifier
@Retention(RUNTIME)
@Target({FIELD,PARAMETER,METHOD,TYPE})
public @interface Dao {
    }

And here is our producer responsible of creating a baseDao with a setted Entity based on the InjectionPoint ParameterizedType:

public class DaoProducer implements Serializable {

    private static final long serialVersionUID = 1L;

    @Produces
    @Dependent//must be dependent pseudoScope cause baseDao is a SLB
    @Dao
    public <ID, T extends BaseEntity> BaseDao<T, ID> produce(InjectionPoint ip, BeanManager bm) {
        if (ip.getAnnotated().isAnnotationPresent(Dao.class)) {
            BaseDao<T, ID> genericDao = (BaseDao<T, ID>)  this.getBeanByName("baseDao", bm);//ask bean manager for a instance of GenericDao
            ParameterizedType type = (ParameterizedType) ip.getType();
            Type[] typeArgs = type.getActualTypeArguments();
            Class<T> entityClass = (Class<T>) typeArgs[0];
            genericDao.setEntityClass(entityClass);
            return genericDao;
        }
        throw new IllegalArgumentException("Annotation @Dao is required when injecting BaseDao");
    }

    public Object getBeanByName(String name, BeanManager bm) { // eg. name=availableCountryDao{
        Bean bean = bm.getBeans(name).iterator().next();
        CreationalContext ctx = bm.createCreationalContext(bean); // could be inlined below
        Object o = bm.getReference(bean, bean.getBeanClass(), ctx); // could be inlined with return
        return o;
    }

}

The ‘secret’ here is that we are infering the Dao’s entity in InjectionPoint so when we Inject BaseDao with:

  @Inject @Dao BaseDao<User,Long> baseUserDao;

the (Class<T>) typeArgs[0]; in line 13 will return User.class and we set it in the Dao. Below is a concrete bean using our Dao to perform crud operations:

@Named
@ViewAccessScoped
public class CarBean implements Serializable{

    private List carList;
    private List filteredValue;//datatable filteredValue attribute
    private Integer id;
    private Car car;

    @Inject CarDao carDao;

    @Inject @Dao
    BaseDao<Car,Integer> genericDao;//reuse generic dao for basic crud operation in various entities
//    @Inject @Dao
//    BaseDao<Person,Long> genericDao;
//    @Inject @Dao
//    BaseDao<Client,IDClass> genericDao;

    @PostConstruct
    public void init(){
        if(genericDao.findAll().isEmpty()){
            for (int i = 1; i < 10; i++) {
                Car c = new Car("Car"+i, i);
                genericDao.insert(c);
            }
        }
        //same as above
//         if(carDao.findAll().isEmpty()){
//            for (int i = 0; i < 10; i++) {
//                Car c = new Car("Car"+i, i);
//                carDao.insert(c);
//            }
//        }

    }

    public List getCarList(){
        if(carList == null){
            carList = carDao.findAll();
        }
        return carList;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Car getCar() {
        if(car == null){
            car = new Car();
        }
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public void findCarById(Integer id){
         car = genericDao.find(id);
    }

    public List getFilteredValue() {
        return filteredValue;
    }

    public void setFilteredValue(List filteredValue) {
        this.filteredValue = filteredValue;
    }

    public void remove(){
        if(car != null && car.getId() != null){
            genericDao.delete(car.getId());
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Car "+car.getModel() +" removed successfully"));
            clear();
        }
    }

    public void update(){
        String msg;
        if(car.getId() == null){
             genericDao.insert(car);
             msg = "Car "+car.getModel() +" created successfully";
        }
        else{
           genericDao.update(car);
           msg = "Car "+car.getModel() +" updated successfully";
        }
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(msg));
        clear();//reload car list
    }

    public void clear(){
        car = new Car();
        carList = null;
        id = null;
    }

    public void onRowSelect(SelectEvent event) {
        setId(((Car) event.getObject()).getId());
        findCarById(getId());
    }

    public void onRowUnselect(UnselectEvent event) {
        car = new Car();
    }
}

Addendum

Just a small addendum(which is not that small) there was an issue with the above implementation which showed up when using BaseDao to crud more than one entity in the same bean. The bug was caused because i was storing EntityClass in a stateless session bean(BaseDao), although CDI produces different instances for each injection point the container was returning the same session bean(from the pool of BaseDaos) for each produced bean. The solution was to remove EntityClass from BaseDao and put it in a CDI Bean called CrudDao which has a composion association with BaseDao making it really stateless(as it should be).Here is the CrudDao:

@Named("crudDao")
public class CrudDao<T extends BaseEntity<ID>, ID> implements Serializable{

    @Inject
    protected BaseDao<T,ID> dao;

    protected Class<T> entityClass;

   public Class<T> getEntityClass() {
        if (entityClass == null) {
            //only works if one extends CrudDao, we will take care of it with CDI
            entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
        return entityClass;
    }

    public void setEntityClass(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    public EntityManager getEntityManager(){
        return dao.getEntityManager();
    }

    public T find(ID id){
        return dao.find(id, getEntityClass());
    }

    public void delete(ID id){
         dao.delete(id, getEntityClass());
    }

    public T update(T t){
        return dao.update(t);
    }

    public void insert(T t){
        dao.insert(t);
    }

    public List<T> findAll(){
        return dao.findAll(getEntityClass());
    }

    public List<T> findWithNamedQuery(String namedQueryName){
        return dao.findWithNamedQuery(namedQueryName);
    }
}

References:

[1]http://www.adam-bien.com/roller/abien/entry/generic_crud_service_aka_dao

[2http://www.infoq.com/news/2007/09/jpa-dao

[3]http://www.adam-bien.com/roller/abien/entry/jpa_ejb3_killed_the_dao

[4]http://www.rponte.com.br/2009/06/08/no-more-daos/ [PT_BR]

[5]]http://tutorials.jenkov.com/java-persistence/dao-design-pattern.html