Несколько аннотаций одного и того же типа на одном элементе?
Я пытаюсь побить две или более аннотации одного и того же типа в одном элементе, в данном случае - методе. Вот приблизительный код, с которым я работаю:
public class Dupe {
public @interface Foo {
String bar();
}
@Foo(bar="one")
@Foo(bar="two")
public void haha() {}
}
При компиляции выше, javac жалуется на дублируемую аннотацию:
[email protected]:~/work/daybreak$ javac Dupe.java
Dupe.java:5: duplicate annotation
Можно ли просто повторять аннотации? Педально говоря, не являются ли два экземпляра @Foo выше разных из-за того, что их содержимое отличается?
Если вышеизложенное невозможно, какие-то возможные обходные пути?
ОБНОВЛЕНИЕ: меня попросили описать мой вариант использования. Здесь идет.
Я создаю синтаксический сахаристый механизм для "сопоставления" POJO для хранения таких хранилищ, как MongoDB. Я хочу, чтобы индексы указывались как аннотации на геттеры или сеттеры. Здесь надуманный пример:
public class Employee {
private List<Project> projects;
@Index(expr = "project.client_id")
@Index(expr = "project.start_date")
public List<Project> getProjects() { return projects; }
}
Очевидно, что я хочу иметь возможность быстро находить экземпляры Employee различными свойствами проекта. Я могу либо указать @Index дважды с разными значениями expr(), либо принять подход, указанный в принятом ответе. Несмотря на то, что Hibernate делает это, и это не считается взломом, я думаю, что по-прежнему имеет смысл хотя бы разрешить иметь несколько аннотаций одного и того же типа в одном элементе.
Ответы
Ответ 1
Две или более аннотации одного типа не допускаются. Однако вы можете сделать что-то вроде этого:
public @interface Foos {
Foo[] value();
}
@Foos({@Foo(bar="one"), @Foo(bar="two")})
public void haha() {}
Вам понадобится специальная обработка аннотации Foos в коде.
btw, я только что использовал это 2 часа назад для решения одной и той же проблемы:)
Ответ 2
В Java 8 (выпущен в марте 2014 года) можно писать повторяющиеся/дублированные аннотации. См. http://docs.oracle.com/javase/tutorial/java/annotations/repeating.html.
Ответ 3
Как сказал sfussenegger, это невозможно.
Обычным решением является построить "множественную" аннотацию, которая обрабатывает массив предыдущей аннотации. Обычно он называется одним и тем же, с суффиксом 's'.
Кстати, это очень полезно в больших публичных проектах (например, Hibernate), поэтому его нельзя рассматривать как взломать, а скорее - правильное решение для этой потребности.
В зависимости от ваших потребностей было бы лучше позволить вашей более ранней аннотации обрабатывать несколько значений.
Пример:
public @interface Foo {
String[] bars();
}
Ответ 4
http://docs.oracle.com/javase/tutorial/java/annotations/repeating.html
Начиная с Java8 вы можете описать повторяемые аннотации:
@Repeatable(FooValues.class)
public @interface Foo {
String bar();
}
public @interface FooValues {
Foo[] value();
}
Примечание: value
- обязательное поле для списка значений.
Теперь вы можете использовать аннотации, повторяя их вместо заполнения массива:
@Foo(bar="one")
@Foo(bar="two")
public void haha() {}
Ответ 5
Помимо других упомянутых способов, в Java8 есть еще один более подробный способ:
@Target(ElementType.TYPE)
@Repeatable(FooContainer.class)
@Retention(RetentionPolicy.RUNTIME)
@interface Foo {
String value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface FooContainer {
Foo[] value();
}
@Foo("1") @Foo("2") @Foo("3")
class Example{
}
Пример по умолчанию получает, FooContainer
как аннотацию
Arrays.stream(Example.class.getDeclaredAnnotations()).forEach(System.out::println);
System.out.println(Example.class.getAnnotation(FooContainer.class));
Оба вышепечатаемых:
@com.FooContainer(value = [@com.Foo(value = 1), @com.Foo(value = 2), @com.Foo(value = 3)])
@com.FooContainer(value = [@com.Foo(value = 1), @com.Foo(value = 2), @com.Foo(value = 3)])
Ответ 6
Если у вас есть только один параметр "bar", вы можете назвать его "значение". В этом случае вам не придется писать имя параметра вообще, когда вы его используете следующим образом:
@Foos({@Foo("one"), @Foo("two")})
public void haha() {}
немного короче и аккуратно, imho..
Ответ 7
объединение других ответов в простейшую форму... аннотация с простым списком значений...
@Foos({"one","two"})
private String awk;
//...
public @interface Foos{
String[] value();
}