2010-06-12 9 views
11

Dada una interfaz genérica comoanotación para poner a disposición de tipo genérico

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

Me gustaría crear una subinterfaz que especifica el parámetro de tipo:

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

La aplicación necesita conocer la plantilla real tipo de parámetro, pero por supuesto el medio de borrado de tipo no está disponible en tiempo de ejecución. ¿Hay alguna anotación que pueda incluir para declarar el tipo de interfaz? Algo así como

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

La aplicación entonces podría alcanzar esta anotación desde la interfaz y lo utilizan como un sustituto para el acceso de tipo genérico en tiempo de ejecución.

Algunos antecedentes:

Esta interfaz se implementa utilizando JDK proxies dinámicos como se indica here. La versión no genérica de esta interfaz ha funcionado bien, pero sería mejor utilizar genéricos y no tener que crear los métodos en una subinterfaz solo para especificar el tipo de objeto de dominio. Los genéricos y los proxies se encargan de la mayoría de las cosas, pero el tipo real es necesario en tiempo de ejecución para implementar el método newInstance, entre otros.

+1

¿Has intentado simplemente escribir tu propia anotación? –

+0

@Lauri - No he hecho lo mío, pero podría hacer eso, veo muchas preguntas sobre genéricos y frustraciones sobre el borrado de tipos, así que espero que esto ya se haya hecho. – mdma

Respuesta

7

Es posible encontrar el argumento de tipo real de la sub-interfaz Dao (CustomerDAO), invocando el método siguiente:

import java.lang.reflect.ParameterizedType; 

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

Cuando se llama a ella como

Class<?> domainClass = getDomainClass(daoInterface); 

con daoInterface == CustomerDAO.class , entonces obtendrá domainClass == Customer.class.

En mi implementación, un DaoFactory realiza esta llamada y utiliza el domainClass como un argumento constructor para el DaoInvocationHandler.

+1

¡Gracias! Esta es la solución. De acuerdo con http: //blog.springsource.com/2006/09/29/exploiting-generics-metadata/no se borra toda la información genérica, en particular, se mantiene la información estática. – mdma

1

La implementación necesita conocer el tipo de parámetro de la plantilla real.

Sin duda, cualquier implementación de CustomerDao implícitamente sabe que el parámetro tipo es Customer. Está implementando DomainObjectDAO<Customer> no DomainObjectDAO<T>.

Los problemas solo surgen si la clase CustomerDao amplía una clase abstracta genérica, y esa clase abstracta genérica necesita conocer el tipo real de T. Pero puede tratar eso pasando el objeto Class para T (en este caso Customer.class) a la superclase como un argumento de constructor.

+0

Iba a escribir eso en la pregunta de que podía pasar el tipo real como un constructor a InvocationHandler, pero me preguntaba si hay una anotación para hacer el mismo trabajo: el tipo pertenece a la interfaz y no a la implementación. – mdma

Cuestiones relacionadas