java – GenericDAO – Is it correct?

Question:

I'm implementing a simple GenericDAO as below, but I feel like I'm doing something wrong, it works but I feel like there's something wrong anyway, could you help me?

I created an interface like this:

public interface GenericDAO<T, ID> {
    public List<T> listaTodos(Class<T> clazz);
    public List<T> listaComLimite(Class<T> clazz, Integer limite);
    public T porId(Class<T> clazz, ID id);
    public void adiciona(T t);
    public T grava(T t);
    public void remove(Class<T> clazz, ID id);
}

Then I created another interface (more specific), that is, with what is not generic, but as we can see this extends from the previous GenericDAO :

public interface TestDAO extends GenericDAO<Test, Long> {
    public Test buscaPorNome(String nome);
}

Below I am testing how it would be used:

public void getTest(){
    Test teste = testDAO.porId(Test.class, id);
}

It sounds silly, but when I extended GenericDAO I already passed the target class:

extends GenericDAO<Test, Long>

The question is, why when I'm going to use it, do I need to pass it again, like this?

Test teste = testDAO.porId(Test.class, id);

Doesn't that feel wrong?

Answer:

There is nothing wrong with your code. Many frameworks use this approach with parameters of type Class<T> to get around the limitations of Java's generic implementation (in short, the problem is that <T> is "erased" at runtime).

That said, there is a known workaround for this type of situation. If your classes extend a generic base class you can extract that generic type from the superclass through reflection.

For example, if you have a GenericDaoImpl<T> class and a specific subclass SpecificDaoImpl extends GenericDaoImpl<Specific> ):

private final Class<T> minhaClasse; 

public GenericDaoImpl() {
    minhaClasse = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
            .getActualTypeArguments()[0];

}

The advantage here is that you don't have to pass the class type ever.

Alternatively, to not have to deal with reflection, you can also use the constructor of the generic class to receive the type (and specify the type as an argument in the constructor of the specific class once):

private final Class<T> minhaClasse;

public GenericDaoImpl(Class<T> minhaClasse) {
    this.minhaClasse = minhaClasse;
}

// E na classe específica
public SpecificDaoImpl() {
    super(TipoDaMinhaClasseEspecífica);
}

I can't tell you which implementation would be "more correct". It is worth using whichever is most practical in your case.


Source: SOen – Get generic type of class at runtime .

Scroll to Top