Несколько аннотаций одного и того же типа на одном элементе?

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

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 часа назад для решения одной и той же проблемы:)

Ответ 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();
}