2011-10-13 15 views
66

Estoy explorando anotaciones y llegué a un punto en el que algunas anotaciones parecen tener una jerarquía entre ellas.¿Hay algo así como herencia de anotación en java?

Estoy usando anotaciones para generar código en el fondo para Tarjetas. Existen diferentes tipos de Tarjeta (por lo tanto, diferentes códigos y anotaciones), pero hay ciertos elementos que son comunes entre ellos como un nombre.

@Target(value = {ElementType.TYPE}) 
public @interface Move extends Page{ 
String method1(); 
String method2(); 
} 

Y esta sería la anotación común:

@Target(value = {ElementType.TYPE}) 
public @interface Page{ 
String method3(); 
} 

En el ejemplo anterior yo esperaría Mover a heredar metodo3 pero me sale un aviso diciendo que se extiende no es válido con anotaciones. Estaba tratando de tener una Anotación que amplía una base común pero eso no funciona. ¿Es eso posible o solo es un problema de diseño?

+0

La herencia de anotaciones parece ser una herramienta imprescindible para crear una DSL basada en anotaciones. Qué pena que la herencia de la anotación no sea compatible. – Ceki

+0

Estoy de acuerdo, parece una cosa natural de hacer. Especialmente después de comprender la herencia en Java, esperas que se aplique a todo. – javydreamercsw

Respuesta

49

Lamentablemente, no. Aparentemente tiene algo que ver con los programas que leen las anotaciones en una clase sin cargarlas por completo. Ver Why is not possible to extend annotations in Java?

Sin embargo, los tipos heredan las anotaciones de su superclase si esas anotaciones son @Inherited.

También, a menos que necesite esos métodos para interactuar, sólo podría apilar las anotaciones en su clase:

@Move 
@Page 
public class myAwesomeClass {} 

¿Hay alguna razón por la que no iba a funcionar para usted?

+1

Eso fue lo que pensé, pero estaba tratando de simplificar las cosas. Tal vez aplicar el Común a una clase abstracta haría el truco ... – javydreamercsw

+1

Sí, eso parecía bastante inteligente también. ¡Buena suerte! – andronikus

33

Puede anotar su anotación con una anotación base en lugar de la herencia. Esto es used in Spring framework.

Para dar un ejemplo

@Target(value = {ElementType.ANNOTATION_TYPE}) 
public @interface Vehicle { 
} 

@Target(value = {ElementType.TYPE}) 
@Vehicle 
public @interface Car { 
} 

@Car 
class Foo { 
} 

A continuación, puede comprobar si una clase se anota con Vehicle usando Spring's AnnotationUtils:

Vehicle vehicleAnnotation = AnnotationUtils.findAnnotation (Foo.class, Vehicle.class); 
boolean isAnnotated = vehicleAnnotation != null; 

Este método se implementa como:

public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) { 
    return findAnnotation(clazz, annotationType, new HashSet<Annotation>()); 
} 

@SuppressWarnings("unchecked") 
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) { 
    try { 
     Annotation[] anns = clazz.getDeclaredAnnotations(); 
     for (Annotation ann : anns) { 
      if (ann.annotationType() == annotationType) { 
       return (A) ann; 
      } 
     } 
     for (Annotation ann : anns) { 
      if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) { 
       A annotation = findAnnotation(ann.annotationType(), annotationType, visited); 
       if (annotation != null) { 
        return annotation; 
       } 
      } 
     } 
    } 
    catch (Exception ex) { 
     handleIntrospectionFailure(clazz, ex); 
     return null; 
    } 

    for (Class<?> ifc : clazz.getInterfaces()) { 
     A annotation = findAnnotation(ifc, annotationType, visited); 
     if (annotation != null) { 
      return annotation; 
     } 
    } 

    Class<?> superclass = clazz.getSuperclass(); 
    if (superclass == null || Object.class == superclass) { 
     return null; 
    } 
    return findAnnotation(superclass, annotationType, visited); 
} 

AnnotationUtils también contiene métodos adicionales para buscar anotaciones sobre métodos y otros elementos anotados. La clase Spring también es lo suficientemente potente como para buscar a través de métodos en puente, proxies y otros casos de esquina, particularmente los encontrados en Spring.

+11

Incluya una explicación de cómo procesar dichas anotaciones. –

+1

Puede usar Spring's AnnotationUtils.findAnnotation (..), ver: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html#findAnnotation-java .lang.Class-java.lang.Class- – rgrebski

5

Además de la respuesta de Grygoriys de anotaciones de anotaciones.

Puede verificar, p. métodos para contener una anotación de @Qualifier (o una anotación anotado con @Qualifier) ​​por este bucle:

for (Annotation a : method.getAnnotations()) { 
    if (a.annotationType().isAnnotationPresent(Qualifier.class)) { 
     System.out.println("found @Qualifier annotation");//found annotation having Qualifier annotation itself 
    } 
} 

Lo que estamos haciendo básicamente, es conseguir que todas las anotaciones presentes en el método y de las anotaciones que obtiene su escribe y verifica esos tipos si están anotados con @Qualifier. Su anotación debe ser Target.Anotation_type habilitado también para que funcione.

+0

¿En qué se diferencia esto de la respuesta de Grygoriy? –

Cuestiones relacionadas