1
votes

I need brains here! :p

I have an interface IDAO< T ,K >, T is the entity class and K the primary key class.

I have developped a concrete class GenericDAO< T ,K >, that provides CRUD operations and Criteria Queries with automatic fetches (I have created an aspect @Joinfetch I use on entitiy relations). I can show the code if you want but it's not the subject :).

Here the Factory that produces GenericDAOs:

public class GenericDAOProducer {

@PersistenceContext
EntityManager em;

@Produces
@Default
public <T, K> IDAO<T, K> producesGenericDAO(
        final InjectionPoint injectionPoint) {
    final ParameterizedType type = (ParameterizedType) injectionPoint
            .getType();
    // Because of the new, i got to inject the class and the entity manager
    // manualy
    final IDAO<T,K> dao = new GenericDAO<T, K>(this.em,
            (Class) type.getActualTypeArguments()[0]);
    dao.init(); //cool stuff here to prepare some criteria queries
    return dao;
}
}

Sometimes I need another implementations for DAOs (for complex fetching for exemple). Those implementations expose their methods by the IDAO façade too. I want those DAOs to be injected the same way that the GenericDAO.

Here is the feature that I want in an exemple:

I need an injection of an implementation of IDAO< Person, Long> somewhere. If exists a class implements IDAO< Person, Long> then I want CDI to choose this implementation. Else if no implementation exist for IDAO< Person, Long> I want CDI to choose the GenericDAO< Person, Long > produced by the Factory.

It's quite difficult for me to explain that in english. I hope you will understand my problem.

Do you have best practices to do that?

Thank you!

1
I created something very cool to do that! I'll share soon :)Saveriu CIANELLI
You might want to check out DeltaSpike Data for generic DAOs based on CDI.Harald Wellmann
It's a very interresting API thanks! But I don't think it creates strong typed DAO without class at all. You need to declare at least one @Repository by entity. The thing is my application stocks a lot of data and every month I need to add an entity class with its relations. Then I have to code classes in every level. With my pattern, I don't need to code a DAO at all exept if I want to override or add some methods.Saveriu CIANELLI

1 Answers

1
votes

I need two @Qualifier

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


@Qualifier
@Retention(RUNTIME)
@Target({ METHOD, FIELD, PARAMETER, TYPE })
public @interface Specific {
Class<?> classe();
}

The IDAO Interface

public interface IDAO<T, PK> extends Serializable {

public abstract T create(T entity) throws DAOException;

public abstract T edit(T entity) throws DAOException;

public abstract void remove(T entity) throws DAOException;

public abstract T find(PK id) throws DAOException;

public abstract T findWithFetch(PK id) throws DAOException;

public abstract List<T> findAll();

public abstract T getRef(PK id);
}

The IDefaultDAO

public interface IDefaultDAO<T, PK> extends IDAO<T, PK> {
public void setEntityClass(final Class<T> entityClass);
}

The Abstract DAO

public abstract class AbstractDAO<T, PK> implements IDAO<T, PK> {

@PersistenceContext
protected EntityManager em;

@Inject
protected transient Logger logger;

protected Class<T> entityClass;

protected final Class<T> getEntityClass() {
    if (this.entityClass == null) {
        this.entityClass = ((Class) ((ParameterizedType) this.getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0]);

    }
    return this.entityClass;
}

//methods implementations
}

The Default DAO

@Generic
public class DefaultDAO<T, PK> extends AbstractDAO<T, PK> implements
    IDefaultDAO<T, PK> {

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

A specific DAO

@Specific(classe=Delegation.class)
public class DelegationDAO extends AbstractDAO<Delegation, Integer>
implements IDAO<Delegation, Integer> {
// do things differently
}

The DAO Producer

public class GenericDAOProducer {

@Inject
private transient Logger logger;

@Produces
public <T, PK> IDAO<T, PK> producesDAO(final InjectionPoint injectionPoint,
        @Generic final IDefaultDAO<T, PK> genericDAO,
        @Any Instance<IDAO<T, PK>> specDAOInstance) {

    // JPA Class (T)
    final ParameterizedType type = (ParameterizedType) injectionPoint
            .getType();
    final Class<T> entityClass = (Class) type.getActualTypeArguments()[0];

    this.logger.info("Search DAO " + entityClass);

    // Search specific DAO

    specDAOInstance = specDAOInstance.select(new SpecificLiteral(
            entityClass));

    if ((specDAOInstance != null) && !specDAOInstance.isAmbiguous()
            && !specDAOInstance.isUnsatisfied()) {
        this.logger.info("Implementation found! ");
        return specDAOInstance.get();
    } else {

        this.logger
                .info("Implementation not found! Return generic DAO."
                        + entityClass);

        genericDAO.setEntityClass(entityClass);
        return genericDAO;
    }
  }
}