web-dev-qa-db-fra.com

Existe-t-il quelque chose comme l'héritage d'annotation en java?

J'explore les annotations et j'en suis arrivé à un point où certaines annotations semblent avoir une hiérarchie entre elles.

J'utilise des annotations pour générer du code en arrière-plan pour les cartes. Il existe différents types de cartes (donc des codes et des annotations différents), mais certains éléments sont communs parmi eux, comme un nom.

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

Et ce serait l'annotation commune:

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

Dans l'exemple ci-dessus, je m'attendrais à ce que Move hérite de method3, mais un avertissement m'indique que extend n'est pas valide avec les annotations. J'essayais d'avoir une annotation qui étend une base commune mais cela ne fonctionne pas. Est-ce même possible ou s'agit-il simplement d'un problème de conception?

101
javydreamercsw

Malheureusement non. Apparemment, cela a quelque chose à voir avec les programmes qui lisent les annotations sur une classe sans les charger complètement. Voir Pourquoi n'est-il pas possible d'étendre des annotations en Java?

Cependant, les types héritent des annotations de leur super-classe si ces annotations sont @Inherited .

De plus, à moins que vous n'ayez besoin de ces méthodes pour interagir, vous pouvez simplement empiler les annotations sur votre classe:

@Move
@Page
public class myAwesomeClass {}

Y a-t-il une raison qui ne fonctionnerait pas pour vous?

67
andronikus

Vous pouvez annoter votre annotation avec une annotation de base au lieu d'un héritage. Ceci est tilisé dans le framework Spring .

Pour donner un exemple

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

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

@Car
class Foo {
}

Vous pouvez alors vérifier si une classe est annotée avec Vehicle en utilisant AnnotationUtils de Spring :

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

Cette méthode est implémentée comme:

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 contient également des méthodes supplémentaires pour rechercher des annotations sur des méthodes et d'autres éléments annotés. La classe Spring est également assez puissante pour effectuer une recherche dans des méthodes pontées, des mandataires et d'autres cas critiques, en particulier ceux rencontrés au printemps.

54
Grygoriy Gonchar

En plus de la réponse de Grygoriys des annotations annotées.

Vous pouvez vérifier par exemple méthodes pour contenir une annotation @Qualifier (ou une annotation annotée avec @Qualifier) ​​par cette boucle:

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

Ce que vous faites en gros, c’est d’obtenir toutes les annotations présentes sur la méthode et de ces annotations, vous obtenez leurs types et vérifiez ces types s’ils sont annotés avec @Qualifier. Pour que cela fonctionne, votre annotation doit également être Target.Annotation_type.

5
philnate