Как аннотация метода 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.
Ответы
Ответ 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