Почему невозможно расширить аннотации в Java? - PullRequest
218 голосов
/ 26 октября 2009

Я не понимаю, почему в аннотациях Java нет наследования, так же как и в классах Java. Я думаю, это было бы очень полезно.

Например: я хочу знать, является ли данная аннотация валидатором. С наследованием я мог бы рефлексивно перемещаться по суперклассам, чтобы знать, расширяет ли эта аннотация ValidatorAnnotation. Иначе как мне этого добиться?

Итак, кто-нибудь может дать мне причину этого дизайнерского решения?

Ответы [ 8 ]

158 голосов
/ 29 октября 2009

О причине, по которой он не был спроектирован таким образом, вы можете найти ответ в JSR 175 FAQ по проектированию, где написано:

Почему вы не поддерживаете подтипы аннотаций (когда один тип аннотации расширяет другой)?

усложняет тип аннотации система, и делает это намного больше трудно написать «Специальные инструменты».

...

«Специальные инструменты» - Программы, которые запрашивают известные типы аннотаций произвольных внешние программы. Генераторы заглушки, например, попадают в эту категорию. Эти программы будут читать аннотированные классы без загрузки их в виртуальная машина, но загрузит интерфейсы аннотаций.

Так что, да, я думаю, причина в том, что это просто ПОЦЕЛУЙ. В любом случае, похоже, что эта проблема (наряду со многими другими) рассматривается как часть JSR 308 , и вы даже можете найти альтернативный компилятор с этой функциональностью, уже разработанной Mathias Ricken .

66 голосов
/ 28 октября 2009

Расширяемые аннотации эффективно добавят бремя определения и поддержки другой системы типов. И это будет довольно уникальная система типов, так что вы не сможете просто применить парадигму типа ОО.

Продумайте все вопросы, когда вы вводите полиморфизм и наследование в аннотацию (например, что происходит, когда поданнотация изменяет спецификации метааннотации, такие как сохранение?)

И все это добавляет сложности для какого варианта использования?

Вы хотите знать, относится ли данная аннотация к категории?

Попробуйте это:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    String category();
}

@Category(category="validator")
public @interface MyFooBarValidator {

}

Как видите, вы можете легко группировать и классифицировать аннотации без лишних усилий, используя предоставленные средства.

Итак, KISS является причиной отказа от введения системы типов мета-типов в язык Java.

[p.s. править]

Я использовал String просто для демонстрации и ввиду открытой аннотации мета. Для вашего собственного данного проекта вы, очевидно, можете использовать перечисление типов категорий и указать несколько категорий («множественное наследование») для данной аннотации. Обратите внимание, что значения являются полностью поддельными и только для демонстрационных целей:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    AnnotationCategory[] category();
}
public enum AnnotationCategory {
    GENERAL,
    SEMANTICS,
    VALIDATION,
    ETC
}

@Category(category={AnnotationCategory.GENERAL, AnnotationCategory.SEMANTICS})
public @interface FooBarAnnotation {

}

11 голосов
/ 28 октября 2009

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

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

Единственный вариант использования, который я мог видеть, что наследование помогло бы, это если бы вы хотели иметь возможность получать аннотации по супертипу, но это добавило бы целую кучу сложности, потому что данный метод или тип может иметь две такие аннотации это означает, что массив должен быть возвращен вместо одного объекта.

Так что я думаю, что окончательный ответ заключается в том, что варианты использования являются эзотерическими и усложняют более стандартные варианты использования, делая его не стоящим.

5 голосов
/ 20 февраля 2014

Разработчики поддержки аннотаций Java сделали ряд «упрощений» в ущерб сообществу Java.

  1. Отсутствие подтипов аннотаций делает многие сложные аннотации излишне уродливыми. Нельзя просто иметь атрибут внутри аннотации, который может содержать одну из трех вещей. Нужно иметь три отдельных атрибута, что смущает разработчиков и требует проверки во время выполнения, чтобы гарантировать, что используется только один из трех.

  2. Только одна аннотация данного типа для каждого сайта. Это привело к совершенно ненужному шаблону аннотации коллекции. @Validation и @Validations, @Image и @Images и т. Д.

Второй исправляется в Java 8, но уже слишком поздно. Многие фреймворки были написаны на основе того, что было возможно в Java 5, и теперь эти бородавки API остаются здесь надолго.

2 голосов
/ 10 мая 2013

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

У меня была ситуация, когда я хотел имитировать GET, POST, PUT и DELETE в веб-приложении. Я так сильно хотел иметь «супер» аннотацию, которая называлась «HTTP_METHOD». Позже меня осенило, что это не имеет значения. Что ж, мне пришлось согласиться с использованием скрытого поля в HTML-форме для идентификации DELETE и PUT (потому что POST и GET были доступны в любом случае).

На стороне сервера я искал скрытый параметр запроса с именем "_method". Если значение было PUT или DELETE, то оно переопределяет связанный метод HTTP-запроса. Сказав это, не имело значения, нужно ли мне расширять аннотацию, чтобы выполнить работу. Все аннотации выглядели одинаково, но на стороне сервера они обрабатывались по-разному.

Так что в вашем случае снимите зуд, чтобы продлить аннотации. Относитесь к ним как к «маркерам». Они «представляют» некоторую информацию и необязательно «манипулируют» некоторой информацией.

2 голосов
/ 26 октября 2009

Никогда не задумывался об этом, но ... кажется, вы правы, с наследованием аннотаций проблем нет (по крайней мере, я не вижу проблем с этим).

О вашем примере с 'validator' annotation - вы можете использовать 'meta-annotation' подход тогда. То есть Вы применяете определенную метааннотацию ко всему интерфейсу аннотаций.

2 голосов
/ 26 октября 2009

Одна вещь, о которой я мог подумать, это возможность иметь несколько аннотаций. Таким образом, вы можете добавить валидатор и более конкретную аннотацию в одном месте. Но я могу ошибаться :) 1001 *

1 голос
/ 26 октября 2009

та же проблема у меня. Нет, ты не можешь. Я «дисциплинировал» себя, чтобы записывать свойства в аннотации, чтобы соблюдать некоторые стандарты, поэтому снаружи, когда вы получаете аннотацию, вы можете «узнать», какой это вид аннотации, по свойствам, которые она имеет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...