2011-10-13 16 views
66

Sto esplorando le annotazioni e ho raggiunto un punto in cui alcune annotazioni sembrano avere una gerarchia tra di esse.C'è qualcosa come Annotation Inheritance in java?

Sto usando le annotazioni per generare codice in background per le Carte. Ci sono diversi tipi di carte (quindi codice e annotazioni differenti) ma ci sono alcuni elementi che sono comuni tra loro come un nome.

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

E questo sarebbe l'Annotazione comune:

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

Nell'esempio di cui sopra mi aspetterei Sposta per ereditare method3 ma ottengo un avvertimento dicendo che si estende non è valida con annotazioni. Stavo cercando di avere un'annotazione che estende una base comune ma che non funziona. È possibile o è solo un problema di progettazione?

+0

L'ereditarietà delle annotazioni sembra un must per creare un DSL basato sulle annotazioni. È un peccato che l'ereditarietà delle annotazioni non sia supportata. – Ceki

+0

Sono d'accordo, sembra una cosa naturale da fare. Soprattutto dopo aver capito l'ereditarietà su Java, ti aspetti che si applichi a tutto. – javydreamercsw

risposta

49

Sfortunatamente, no. Apparentemente ha qualcosa a che fare con programmi che leggono le annotazioni su una classe senza caricarle completamente. Vedere Why is not possible to extend annotations in Java?

Tuttavia, i tipi ereditano le annotazioni della loro superclasse se tali annotazioni sono @Inherited.

Inoltre, a meno che non avete bisogno di quei metodi di interagire, si può solo impilare le annotazioni sulla tua classe:

@Move 
@Page 
public class myAwesomeClass {} 

C'è qualche ragione che non avrebbe funzionato per voi?

+1

Questo era quello che pensavo ma stavo cercando di semplificare le cose. Forse l'applicazione del Common a una classe astratta avrebbe funzionato ... – javydreamercsw

+1

Sì, anche quello sembrava abbastanza intelligente. In bocca al lupo! – andronikus

33

È possibile annotare l'annotazione con un'annotazione di base anziché ereditata. Questo è used in Spring framework.

Per fare un esempio

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

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

@Car 
class Foo { 
} 

È quindi possibile controllare se una classe è annotata con Vehicle utilizzando Spring's AnnotationUtils:

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

Questo metodo è implementato come:

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 contiene anche metodi aggiuntivi per cercare annotazioni su metodi e altri elementi annotati. La classe Spring è anche abbastanza potente da cercare tra i metodi a ponte, i proxy e altri casi d'angolo, in particolare quelli incontrati in primavera.

+11

Si prega di includere una spiegazione su come elaborare tali annotazioni. –

+1

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

5

Oltre alla risposta Grygoriys delle annotazioni annotanti.

È possibile controllare ad es. metodi per contenente un'annotazione @Qualifier (o un'annotazione annotato con @Qualifier) ​​di questo ciclo:

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

Quello che stai facendo in sostanza, è quello di ottenere tutte le annotazioni presenti sul metodo e di quelle annotazioni si ottiene la loro digita e controlla quei tipi se sono annotati con @Qualifier. La tua annotazione deve essere impostata su Target.Annotation_type per funzionare correttamente.

+0

Com'è diverso dalla risposta di Grygoriy? –