Can i do this?

It seems that I missed something using Java Generics, because something that I think is simple, it seems to me that this is impossible. Maybe you can help ...

This is the scenario: I am coding a generic abstract DAO with a simple CRUD operation, so each specific DAO of my application can have it for free:

public abstract DefaultDAO<T,V> { private EntityManager manager; public BaseDAO(EntityManager em) { this.manager = em; } public void create(T entity) { manager.persist(entity); } // You know the others... public T read(V pk) { // Now, here is the problem. // EntityManager signature is: public <T> T find(Class<T> entityClass, Object primaryKey); // So I must provide the type of the object this method will be returning and // the primary key. // resulting object will be T typed and pk type is V type (although is not needed to type it since the method expects an Object) // So... I expected to be allowed to do something like this return manager.find(T, pk); // But it not allowed to use T here. T is not an instance } } 

Now I would go and implement a specific DAO:

 public PersonDAO extends DefaultDAO<PersonEntity, Long> { public PersonDAO(EntityManager em) { super(em); } // CRUD methods are inherited } 

And the client code for my DAO will be:

 EntityManager manager = ... PersonDAO dao = new PersonDAO(manager); Long pk = ..... PersonEntity person = dao.find(pk); // DAO would return a PersonEntity 

When the client executes the code, BaseDAO knows the type of object that it should return and the type of the primary key of this object, because I set it on a specific Tao, but I do not know how to encode the read () method correctly.

I hope you can help. Many thanks!

+4
source share
5 answers

You are trying to use a type parameter as if it is a normal expression. You cannot do this. In other languages, you can get a class for the type parameter at run time, but you cannot in Java due to type erasure.

In this case, you will need to pass the Class<T> at run time - for example, to the constructor:

 public abstract class DefaultDAO<T, V> { private EntityManager manager; private final Class<T> clazz; public DefaultDAO(EntityManager em, Class<T> clazz) { this.manager = em; this.clazz = clazz; } public T read(V pk) { return manager.find(clazz, pk); } } 
+14
source

Java no longer has general class information at runtime (called Type Erasure). What I did was give my abstract Taoist an instance of the generic class.

 public abstract DefaultDAO<T,V> { protected Class<T> genericClass; private EntityManager manager; protected BaseDAO(EntityManager em, Class<T> implclass) { this.manager = em; } public void create(T entity) { manager.persist(entity); } // You know the others... public T read(V pk) { return manager.find(this.getGenericClass(), pk); // But it not allowed to use T here. T is not an instance } public Class<T> getGenericClass() { return genericClass; } } public class Blubb { private String id; // Getters and Stuff... } public class BlubbDao extends DefaultDAO<Blubb, String> { public BlubbDao(EntityManager em) { super(em, Blubb.class); } } 

I cannot promise that this will end, but I hope you understand this idea.

+3
source

There is a way to do this with reflection if your classes follow a consistent class hierarchy from a generic point of view (i.e., any intermediate classes in the inheritance hierarchy between your base class and your specific class use the same general parameters in the same order) .

We use something similar in our abstract class, defined as HibernateDAO, where T is the type of entity and K is PK:

 private Class getBeanClass() { Type daoType = getClass().getGenericSuperclass(); Type[] params = ((ParameterizedType) daoType).getActualTypeArguments(); return (Class) params[0]; } 

which smells a bit, but repels the uselessness of passing a class from a particular implementation in the constructor for awkwardness, insisting that you maintain a type hierarchy this way.

+3
source

I think you can do this:

  public <T> T find(Class<T> clazz, Object id) { return entityManager.find(clazz, id); } 
+3
source

All Articles