79 votes

Comment les annotations de méthodes Java fonctionnent-elles en conjonction avec le remplacement de méthodes ?

J'ai une classe parent Parent et une classe enfant Child défini ainsi :

class Parent {
    @MyAnnotation("hello")
    void foo() {
        // implementation irrelevant
    }
}
class Child extends Parent {
    @Override
    foo() {
        // implementation irrelevant
    }
}

Si j'obtiens un Method référence à Child::foo , sera childFoo.getAnnotation(MyAnnotation.class) donnez-moi @MyAnnotation ? Ou sera-t-il null ?

Je m'intéresse plus généralement à la manière dont l'annotation fonctionne ou non avec l'héritage Java.

95voto

trutheality Points 13261

Copié mot à mot de http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations.html#annotation-inheritance :

Héritage des annotations

Il est important de comprendre les règles relatives à l'héritage des annotations, car elles ont une incidence sur la correspondance des points de jonction basée sur la présence ou l'absence d'annotations.

Par défaut, les annotations ne sont pas héritées. Étant donné le programme suivant

        @MyAnnotation
        class Super {
          @Oneway public void foo() {}
        }

        class Sub extends Super {
          public void foo() {}
        }

Puis Sub n'a pas le MyAnnotation et l'annotation Sub.foo() n'est pas un @Oneway malgré le fait qu'elle surcharge la méthode Super.foo() qui est.

Si un type d'annotation possède la méta-annotation @Inherited alors une annotation de ce type sur une classe fera en sorte que l'annotation soit héritée par les sous-classes. Ainsi, dans l'exemple ci-dessus, si l'annotation MyAnnotation avait le @Inherited l'attribut Sub aurait le MyAnnotation annotation.

@Inherited ne sont pas héritées lorsqu'elles sont utilisées pour annoter autre chose qu'un type. Un type qui implémente une ou plusieurs interfaces n'hérite jamais des annotations des interfaces qu'il implémente.

12voto

Saintali Points 1639

Vous avez déjà trouvé votre réponse : il n'y a aucune disposition pour l'héritage des annotations de méthode dans le JDK.

Mais remonter la chaîne des super-classes à la recherche de méthodes annotées est également facile à mettre en œuvre :

/**
 * Climbs the super-class chain to find the first method with the given signature which is
 * annotated with the given annotation.
 *
 * @return A method of the requested signature, applicable to all instances of the given
 *         class, and annotated with the required annotation
 * @throws NoSuchMethodException If no method was found that matches this description
 */
public Method getAnnotatedMethod(Class<? extends Annotation> annotation,
                                 Class c, String methodName, Class... parameterTypes)
        throws NoSuchMethodException {

    Method method = c.getMethod(methodName, parameterTypes);
    if (method.isAnnotationPresent(annotation)) {
        return method;
    }

    return getAnnotatedMethod(annotation, c.getSuperclass(), methodName, parameterTypes);
}

9voto

jrey.py Points 852

En utilisant Spring Core, vous pouvez résoudre avec

AnnotationUtils.java

2voto

Trevor Robinson Points 3657

Bien que la réponse à la question posée soit que la méthode de Java Method.getAnnotation() ne tient pas compte des méthodes surchargées, il est parfois utile de trouver ces annotations. Voici une version plus complète de la réponse de Saintali que j'utilise actuellement :

public static <A extends Annotation> A getInheritedAnnotation(
    Class<A> annotationClass, AnnotatedElement element)
{
    A annotation = element.getAnnotation(annotationClass);
    if (annotation == null && element instanceof Method)
        annotation = getOverriddenAnnotation(annotationClass, (Method) element);
    return annotation;
}

private static <A extends Annotation> A getOverriddenAnnotation(
    Class<A> annotationClass, Method method)
{
    final Class<?> methodClass = method.getDeclaringClass();
    final String name = method.getName();
    final Class<?>[] params = method.getParameterTypes();

    // prioritize all superclasses over all interfaces
    final Class<?> superclass = methodClass.getSuperclass();
    if (superclass != null)
    {
        final A annotation =
            getOverriddenAnnotationFrom(annotationClass, superclass, name, params);
        if (annotation != null)
            return annotation;
    }

    // depth-first search over interface hierarchy
    for (final Class<?> intf : methodClass.getInterfaces())
    {
        final A annotation =
            getOverriddenAnnotationFrom(annotationClass, intf, name, params);
        if (annotation != null)
            return annotation;
    }

    return null;
}

private static <A extends Annotation> A getOverriddenAnnotationFrom(
    Class<A> annotationClass, Class<?> searchClass, String name, Class<?>[] params)
{
    try
    {
        final Method method = searchClass.getMethod(name, params);
        final A annotation = method.getAnnotation(annotationClass);
        if (annotation != null)
            return annotation;
        return getOverriddenAnnotation(annotationClass, method);
    }
    catch (final NoSuchMethodException e)
    {
        return null;
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X