2009-04-29 14 views
11

Mam sparametryzowaną hibernację dao, która wykonuje podstawowe operacje crud, a gdy jest sparametryzowana, jest używana jako delegat do wykonywania podstawowych operacji crud dla danego dao.Klasa pochodna z Generic T

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

Chcę, aby móc czerpać klasę z T w czasie wykonywania do tworzenia kryteriów zapytań w Hibernate, tak że:

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

wiem:

T.getClass() 

nie istnieje, ale czy istnieje sposób na uzyskanie prawidłowego obiektu klasy z T w czasie wykonywania?

Przyjrzałem się rodzajom i refleksji, ale nie znalazłem odpowiedniego rozwiązania, być może czegoś brakuje.

Dzięki.

Odpowiedz

17

Można przekazać klasę jako argument konstruktora.

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; 
    } 

    // .... 

} 
+0

Tak to jest jedno rozwiązanie mam. Wolałabym móc wyprowadzić klasę z T, jeśli to możliwe, bez dodawania zależności Class. – bowsie

+8

@bowsie: Rozumiem twój ból. Niestety, kompilator kończy kasowanie wszystkich śladów T. Nazywa się to typem erasure: http://java.sun.com/docs/books/tutorial/java/generics/erasure.html –

+0

Ahh okay, dzięki Adam. – bowsie

7

Istnieje sposób, jak dowiedzieć się class typu argumentu T użyciu odbicia:

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

Oto sposób, jak go używać:

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(); 
    } 

} 

Przypuszczam, to tylko działa, gdy twoja ConcreteEntityDao jest bezpośrednią nadklasą z HibernateDao<ConcreteEntity,...>.

Znalazłem go tutaj: www.greggbolinger.com/blog/2008/04/17/1208457000000.html

+1

działa to tylko w metodzie (lokalizacja stosu), która tworzy sparametryzowany obiekt. Nie działa, jeśli otrzymasz sparametryzowany obiekt z innej metody. –

+0

Nie jestem pewien, czy rozumiem. Czy możesz wyjaśnić to nieco bardziej szczegółowo? Czy są jakieś implikacje dla rozwoju aplikacji internetowych? – rdk

+0

Działa to doskonale, gdy podklasujesz klasę generyczną bezpośrednio. Jeśli masz wiele poziomów dziedziczenia, musisz uwzględnić je w 'figureOutPersistentClass' używając' getSuperClass'. –