2013-04-24 16 views
7

Chociaż moje pytanie dotyczy generycznych Java, umieściłem trochę kodu związanego z JPA, aby pokazać rzeczywisty kontekst.Generics Java: jak uzyskać ogólny typ z metody?

Pracuję z zapytaniami opartymi na JPA 2.0 i API opartym na kryteriach. Wszystkie moje zapytania mają ten sam wzorzec (porównywanie prostych atrybutów, brak nawigacji po ścieżce), więc staram się napisać ogólną klasę, aby poradzić sobie z WZP, zachowując logikę biznesową w oddzielnych klasach. Moim celem jest posiadanie metody, która, biorąc pod uwagę typ jednostki i mapę, która przechowuje pary (nazwa pola -> pożądana wartość) definiująca kryteria, zwraca komponent bean (lub zbiór fasoli) z wartością niektórych pól encji .

Wszystkie moje podmioty implementują interfejs Persistible, a wszystkie moje obiekty przenoszenia dziedziczą po QueryBean. Uważam, że te klasy nie są związane z problemem, więc pomijam ich kod.

Poniższy kod jest urywek mojego pierwszego podejścia (należy zakładać cb jest prawidłowym wystąpienie CriteriaBuilder):

protected <T extends QueryBean, TT extends Persistible> Collection<T> executeQueryEntity 
     (Class<T> type, Class<TT> rootType, QueryConfig queryConfig, Map<String, Object> parameters) { 
    // (...) Initialization goes here 

    CriteriaQuery<T> c = cb.createQuery(type); 

    // FROM CLAUSE 
    Root<TT> root = c.from(rootType); 

    // SELECT CLAUSE 
    List<String> constructorParams = queryConfig.getTargetAttributes(); 
    Selection<?>[] selectArray = new Selection<?>[constructorParams.size()]; 
    for (int i = 0; i < constructorParams.size(); i++) { 
     selectArray[i] = root.get(constructorParams.get(i)); 
    } 
    c.select(cb.construct(type, selectArray)); 

    // WHERE CLAUSE 
    for (String filter : parameters.keySet()) { 
     if (queryConfig.getFieldConfiguration().get(filter).compareUsingEquals()) { 
      // SOME PREDICATE 
     } 
     else { 
      // SOME OTHER PREDICATE 
     } 
    } 

    // (...) Rest of the code goes here 
} 

Mój interfejs QueryConfig jest następujący:

public interface QueryConfig { 

List<String> getTargetAttributes(); 
Map<String, FieldConfiguration> getFieldConfiguration(); 

} 

Ponieważ jestem używające już klasy QueryConfig, która dostarcza informacji o zapytaniu (takich jak parametry potrzebne dla konstruktora QueryBean lub informacji o polach encji), pomyślałem, że byłoby miło pobrać typ jednostki z tej klasy, zamiast przekazywać ją jako Cla parametr ss. Wnioskuję z this mowa, że ​​nie można zrobić bezpośrednio, więc próbowałem następujące rozwiązania:

Dodawanie metodę QueryConfig tak:

Class< ? extends Persistible> getTargetEntity(); 

Dodawanie metodę pośrednią tak:

public <T extends QueryBean> Collection<T> queryMany(Class<T> type, QueryConfig config, Map<String, Object> parameters) { 
    executeQueryEntity(type, config.getTargetEntity(), parameters); 
} 

Ale nie będzie się kompilować. Uważam, że powody są tutaj wyjaśnione: Type mismatch for Class Generics, ale właściwie nie rozumiem odpowiedzi. Moje pytania: czy istnieje sposób na uniknięcie podania parametru Class< TT > do metody execute? Czy jest to dobry sposób na rozwiązanie problemu, czy też powinienem to zmienić? Wszelkie poprawki do kodu są również mile widziane!

+1

swój angielski, nawiasem mówiąc, jest rzeczywiście bardzo dobre. Nawet tego nie zauważyłem, dopóki tego nie wskazałeś. – Zyerah

+2

@Telthien Dziękuję, zrobiłem to najlepiej, jak mogłem =) – DiegoAlfonso

+1

Twoja najlepsza przechodzi lepiej niż wielu native speakerów! Wysiłek jest naprawdę doceniany. – Zyerah

Odpowiedz

2

I nie dość dostać powód dlaczego uważasz, że Twoje podejście będzie działać: QueryConfig z Class< ? extends Persistible> getTargetEntity(); dać żadnej informacji typu, które można określić przez kompilator, i dlaczego uważasz, że kompilator może „odgadnąć” typ jesteś powrócisz i zrobisz sprawdzanie dla ciebie?

Jednym ze sposobów można zrobić, to dostarczanie informacji o typie w QueryConfig

public interface QueryConfig <T extends Persistable> { 
    Class<T> getTargetEntity(); 
    List<String> getTargetAttributes(); 
    Map<String, FieldConfiguration> getFieldConfiguration(); 
} 

i metodę queryMany może być jak:

public <T extends QueryBean, TT extends Persistible> 
Collection<T> queryMany(Class<T> type, 
         QueryConfig<TT> config, 
         Map<String, Object> parameters) { 
    executeQueryEntity(type, config.getTargetEntity(), parameters); 
} 
+0

Dziękuję bardzo!Próbowałem czegoś podobnego, ale pominięto parametr typu QueryConfig w sygnaturze queryMany, więc kompilator narzekał na konwersję z klasy na klasę DiegoAlfonso

Powiązane problemy