Подтвердить что ты не робот

Как аннотация метода Java работает в сочетании с переопределением метода?

У меня есть родительский класс Parent и дочерний класс Child, определяемый таким образом:

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

Если я получаю ссылку Method на Child::foo, будет childFoo.getAnnotation(MyAnnotation.class) дать мне @MyAnnotation? Или это будет null?

Мне интереснее узнать, как или с аннотацией работает с наследованием Java.

4b9b3361

Ответ 1

Скопировано дословно из http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations.html#annotation-inheritance:

Наследование аннотаций

Важно понимать правила, связанные с наследованием аннотаций, поскольку они имеют отношение к сопоставлению точек соединения на основе наличия или отсутствия аннотаций.

По умолчанию аннотации не наследуются. Учитывая следующую программу

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

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

Тогда Sub не имеет аннотации MyAnnotation, а Sub.foo() не является @Oneway, несмотря на то, что он переопределяет Super.foo(), который есть.

Если тип аннотации имеет мета-аннотацию @Inherited, то аннотация этого типа в классе приведет к тому, что аннотация будет наследоваться подклассами. Итак, в приведенном выше примере, если тип MyAnnotation имел атрибут @Inherited, то Sub имел бы аннотацию MyAnnotation.

@Inherited аннотации не наследуются при использовании для аннотирования ничего, кроме типа. Тип, реализующий один или несколько интерфейсов, никогда не наследует никаких аннотаций с интерфейсов, которые он реализует.

Ответ 2

Вы уже нашли свой ответ: в JDK не предусмотрена наследование методов-аннотаций.

Но восхождение на суперклассическую цепочку в поисках аннотированных методов также легко реализовать:

/**
 * 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);
}

Ответ 3

В то время как ответ на заданный вопрос заключается в том, что Java Method.getAnnotation() не рассматривает переопределенные методы, иногда полезно находить эти аннотации. Вот более полная версия ответа Saintali, который я сейчас использую:

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;
    }
}

Ответ 4

Используя Spring Core, вы можете разрешить с помощью

AnnotationUtils.java