11

I have a parameterized hibernate dao that performs basic crud operations, and when parameterized is used as a delegate to fulfil basic crud operations for a given dao.

public class HibernateDao <T, ID extends Serializable> implements GenericDao<T, ID>

I want to be able to derive Class from T at runtime to create criteria queries in Hibernate, such that:

public T findByPrimaryKey(ID id) {
    return (T) HibernateUtil.getSession().load(T.getClass(), id);
}

I know:

T.getClass()

does not exist, but is there any way to derive the correct Class object from T at runtime?

I have looked at generics and reflection but have not come up with a suitable solution, perhaps I am missing something.

Thanks.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
bowsie
  • 1,275
  • 3
  • 15
  • 22

2 Answers2

17

You could have the Class passed as a constructor argument.

public class HibernateDao <T, ID extends Serializable> implements GenericDao<T, ID> {

    private final Class<? extends T> type;

    public HibernateDao(Class<? extends T> type) {
        this.type = type;
    }

    // ....

}
Adam Paynter
  • 46,244
  • 33
  • 149
  • 164
  • Yes this is one solution I have. I would prefer to be able to derive the class from T if possible, without adding the Class dependency. – bowsie Apr 29 '09 at 11:52
  • 8
    @bowsie: I understand your pain. Unfortunately, the compiler completes erases all traces of T. It is called type erasure: http://java.sun.com/docs/books/tutorial/java/generics/erasure.html – Adam Paynter Apr 29 '09 at 12:07
  • @AdamPaynter it's really hard to explain erasure to a newbie why can you use the `` that you see right in front of you. – Nishant Aug 22 '12 at 10:21
  • @Nishant: You're right. I was in the same situation when I was learning Java. It *seemed* like it should be there! A violation of the principle of least astonishment. :) – Adam Paynter Aug 22 '12 at 10:57
7

There is the way how to figure out class of type argument T using reflection:

private Class<T> persistentClass = (Class<T>)
    ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];

Here is the way how I use it:

public class GenericDaoJPA<T> implements GenericDao<T> {

    @PersistenceContext
    protected EntityManager entityManager;

    protected Class<T> persistentClass = figureOutPersistentClass();

    private Class<T> figureOutPersistentClass() {
        Class<T> clazz = (Class<T>)((ParameterizedType) (getClass().getGenericSuperclass())).getActualTypeArguments()[0];
        log.debug("persistentClass set to {}", clazz.getName());
        return clazz;
    }

    public List<T> findAll() {
        Query q = entityManager.createQuery("SELECT e FROM " + persistentClass.getSimpleName() + " e");
        return (List<T>) q.getResultList();
    }

}

I suppose this only works when your ConcreteEntityDao is a direct superclass of HibernateDao<ConcreteEntity,...>.

I've found it here: www.greggbolinger.com/blog/2008/04/17/1208457000000.html

rdk
  • 2,833
  • 4
  • 20
  • 12
  • 1
    this only works in method (stack location) that creates the parameterized object. It doesn't work if you receive the parameterized object from another method. – Ran Biron May 21 '09 at 10:41
  • I'm not sure I understand. Could you explain it in a little bit more detail? Are there any implications for web application development? – rdk May 24 '09 at 22:42
  • This works great when you subclass the generic class directly. If you have multiple levels of inheritance, you'll need to account for them in `figureOutPersistentClass` by using `getSuperClass`. – David Harkness Jul 02 '12 at 18:04