I want to reuse my AbstractDAO in a new project, except this time I don't want to use EJB annotations - just CDI ones.
So far, I've been using it like this:
public abstract class AbstractDAO<T> {
@PersistenceContext(unitName = "myUnit")
private EntityManager entityManager;
private Class<T> entityClass;
public AbstractDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
protected EntityManager getEntityManager() {
return entityManager;
}
public void save(T entity) {
entityManager.persist(entity);
}
public void update(T entity) {
entityManager.merge(entity);
}
public void remove(T entity) {
entityManager.remove(entityManager.merge(entity));
}
public T findById(Object id) {
return entityManager.find(entityClass, id);
}
public List<T> findBy(String attrName, Object attrValue) {
// Impl here
}
// [...] Many more search methods
}
And I've been creating a DAO for each Entity, like this for example:
@Stateless
public class UserDAO extends AbstractDAO<User> {
public UserDAO() {
super(User.class);
}
public User findByUsername(String username) {
if (username != null) {
return super.findOneBy("username", username.toLowerCase());
}
return null;
}
}
Now I would like to get rid of the @Stateless annotation. But simply replacing it with a @RequestScoped one won't work because of the non-private constructor with no parameters requirement of JSR-346
How can I refactor my DAO to a pure CDI one ?
Two issues here: CDI beans are not transaction aware by default -unlike EJBs, so you will have to use @Transactional
qualifier if you want to do saves/updates...
Second, your no-arg constructor: you only need to pass the entity class to your abstract class even though you also specify it as a generic argument. You can infer the actual class like this:
public class AbstractDAO<T> {
private transient Class<T> entityClass;
@SuppressWarnings("unchecked")
public AbstractDAO() {
Type generSuperCls = getClass().getGenericSuperclass();
if (generSuperCls instanceof Class) {
generSuperCls = ((Class<?>) generSuperCls).getGenericSuperclass();
}
ParameterizedType parameterizedType = (ParameterizedType) generSuperCls;
Type type = parameterizedType.getActualTypeArguments()[0];
if (type instanceof Class) {
this.entityClass = (Class<T>) type;
} else if (type instanceof ParameterizedType) {
this.entityClass = (Class<T>) ((ParameterizedType) type).getRawType();
}
}
@PersistenceContext
private EntityManager em;
public T getById(Object id) throws ServiceException {
return getEm().find(entityClass, id);
}
// other methods follow
}
As a side note, why do you want to get rid of EJBs? Benchmarks show you get better performance using pooled slsb than cdi and they together very well(every EJB beans is also a CDI bean in jee container).