Чому класи java не успадковують анотації з реалізованих інтерфейсів?


108

Я використовував AOP Guice для перехоплення деяких викликів методів. Мій клас реалізує інтерфейс, і я хотів би зазначити методи інтерфейсу, щоб Guice міг вибрати правильні методи. Навіть якщо тип анотації позначається з класом реалізації Успадкованої анотації, не успадковується анотація, як зазначено в java doc Inherited:

Зауважте також, що ця мета-анотація спричиняє успадкування лише приміток із надкласових класів; анотації на реалізованих інтерфейсах не впливають.

Що може бути причиною цього? Ознайомлення з усіма інтерфейсами, які клас об’єкта реалізує під час виконання, не так вже й важко зробити, тому для цього рішення має бути вагома причина.

Відповіді:


130

Я б сказав, що причина полягає в тому, що в протилежному випадку виникне проблема множинного успадкування.

Приклад:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Inherited
public @interface Baz { String value(); }

public interface Foo{
    @Baz("baz") void doStuff();
}

public interface Bar{
    @Baz("phleem") void doStuff();
}

public class Flipp{
    @Baz("flopp") public void doStuff(){}
}

public class MyClass extends Flipp implements Foo, Bar{}

Якщо я це роблю:

MyClass.class.getMethod("doStuff").getAnnotation(Baz.class).value()

який результат буде? 'baz', 'phleem' або 'flopp'?


З цієї причини анотації на інтерфейсах рідко корисні.


9
анотації на інтерфейсах корисні лише у тому випадку, якщо у вас є рамка, яка їх підтримує. BTW у цьому прикладі getAnnotation () повертає нуль;)
Пітер Лоурі

6
Не знаю, люди. У цьому випадку (якщо помилки не було) я очікував би The field value is ambiguous.подібної помилки компілятора, як і два інтерфейси, що оголошують ту саму константу з різними значеннями. Я знаю, що це не поле, але значення анотацій вирішуються під час компіляції, чи не так? Особливість, якої ми тут відсутні, була б дуже корисною у багатьох випадках. Вибачте за відродження старої публікації, до речі :).
Петро Янечек

7
@Slanec погляньте на те, як джерела Spring ведуть, щоб побачити, як хлопці весни працювали над цими проблемами. Дивіться AnnotationUtils.findAnnotation (метод, annotationType)
Шон Патрік Флойд

1
Я думав написати щось подібне до цього. З деяким видом простого кешування це здається для мене способом. Дякую! У наведеному вище прикладі ви знайдете Fooанотацію 's ( MyClassне має такої, тоді інтерфейси шукаються та приймаються в тому порядку, в якому вони перебувають після implements), а тому друкують "baz". Класно.
Петро Янечек

2
@WChargin правда, просто знадобилося 2 роки, щоб хтось помітив цю помилку :-)
Шон Патрік Флойд

35

Від Javadoc для @Inherited:

Вказує, що тип примітки автоматично успадковується. Якщо в оголошенні типу анотації присутня успадкована мета-анотація, і користувач запитує тип анотації в декларації класу, а в декларації класу немає анотацій для цього типу, то суперклас класу буде автоматично запитуватися на тип анотації. Цей процес буде повторюватися, поки не буде знайдено анотацію для цього типу або не буде досягнуто вершини ієрархії класів (Object). Якщо жоден суперклас не має анотацій для цього типу, то запит вказуватиме на те, що у відповідного класу немає такої анотації. Зауважте, що цей тип мета-анотації не впливає, якщо анотований тип використовується для коментування будь-якого іншого, крім класу. Зауважте також, що ця мета-анотація спричиняє успадкування лише приміток із надкласових класів;

З іншого боку, валідатори JSR 305 роблять певний пошук спадкування. Якщо у вас є ієрархія класів:

//Person.java
@Nonnull
 public Integer getAge() {...}

//Student.java (inherits from Person)
@Min(5)
public Integer getAge() {...}

Тоді ефективна валідація на Student.getAge()це @Nonnull @Min(5). @Nonnullне має @Inheritedмета-анотації.


4
Це має бути обрана відповідь
Анджей Пуртак

3
ваш приклад суперечить вашій відповіді, в якій сказано, що @Inheritedне впливає ні на що, окрім класу,
Олег Міхеєв

@ Успадкована робота лише тоді, коли ви користуєтесь анотацією на Class
Carlos Parker
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.