2010-06-12 25 views
11

Gegeben wieAnnotation zur Verfügung generischer Typ

eine generische Schnittstelle machen
interface DomainObjectDAO<T> 
{ 
    T newInstance(); 
    add(T t); 
    remove(T t); 
    T findById(int id); 
    // etc...  
} 

Ich möchte eine Subschnittstelle erstellen, die den Typ-Parameter gibt:

interface CustomerDAO extends DomainObjectDAO<Customer> 
    { 
     // customer-specific queries - incidental. 
    } 

Die Umsetzung muss die aktuelle Vorlage wissen Parametertyp, aber natürlich ist Typ Löschmittel zur Laufzeit nicht verfügbar. Gibt es eine Anmerkung, die ich zum Deklarieren des Schnittstellentyps hinzufügen könnte? So etwas wie

@GenericParameter(Customer.class) 
    interface CustomerDAO extends DomainObjectDAO<Customer> 
    { 
    } 

Die Umsetzung könnte dann diese Anmerkung von der Schnittstelle holen und verwenden Sie es als Ersatz für die Laufzeit generischen Typen Zugriff.

Einige Hintergrundinformationen:

Diese Schnittstelle implementiert wird JDK dynamische Proxies als here skizziert. Die nicht-generische Version dieser Schnittstelle hat gut funktioniert, aber es wäre schöner, Generics zu verwenden und die Methoden nicht in einer Subschnittstelle zu erstellen, nur um den Domänenobjekttyp anzugeben. Generics und Proxies kümmern sich um die meisten Dinge, aber der tatsächliche Typ wird zur Laufzeit benötigt, um unter anderem die Methode newInstance zu implementieren.

+1

Haben Sie versucht, Ihre eigene Anmerkung zu schreiben? –

+0

@Lauri - Ich habe nicht mein eigenes gemacht, aber ich könnte das tun, ich sehe eine Menge Fragen über Generika und Frustrationen über die Typ-Löschung, also hoffe ich, dass dies bereits geschehen ist. – mdma

Antwort

7

Es ist möglich, die tatsächliche Typargument des Dao Unter Schnittstelle (CustomerDAO) zu finden, die durch die folgende Methode aufrufen:

import java.lang.reflect.ParameterizedType; 

public static Class<?> getDomainClass(final Class<?> daoInterface) { 
    ParameterizedType type = (ParameterizedType) daoInterface.getGenericInterfaces()[0]; 
    return (Class<?>) type.getActualTypeArguments()[0]; 
} 

Wenn Sie es nennen wie

Class<?> domainClass = getDomainClass(daoInterface); 

mit daoInterface == CustomerDAO.class , dann erhalten Sie domainClass == Customer.class.

In meiner Implementierung führt eine DaoFactory diesen Aufruf durch und verwendet domainClass als Konstruktorargument für die DaoInvocationHandler.

+1

Danke! Dies ist die Lösung. Laut http: //blog.springsource.com/2006/09/29/Generieren von Generika-Metadaten/nicht alle generischen Informationen werden gelöscht - insbesondere statische Informationen werden beibehalten. – mdma

1

Die Implementierung muss den tatsächlichen Template-Parametertyp kennen.

Sicher, jede Implementierung von CustomerDao implizit weiß, dass der Typ-Parameter Customer ist. Es implementiert DomainObjectDAO<Customer> nicht DomainObjectDAO<T>.

Probleme werden nur auftreten, wenn die Klasse CustomerDao eine generische abstrakte Klasse erweitert und dass generische abstrakte Klasse den tatsächlichen Typ von T kennen muss. Aber Sie können damit umgehen, indem Sie das Klassenobjekt für T (in diesem Fall Customer.class) als Konstruktorargument an die Oberklasse übergeben.

+0

Ich würde das in der Frage schreiben, dass ich den tatsächlichen Typ als Konstruktor an den InvocationHandler übergeben könnte, aber ich frage mich, ob es eine Annotation für den gleichen Job gibt - der Typ gehört zur Schnittstelle und nicht zur Implementierung. – mdma

Verwandte Themen