Участник аннотации, который содержит другие аннотации?

Я хочу создать пользовательскую аннотацию (используя Java), которая примет другие аннотации в качестве параметра, например:

public @interface ExclusiveOr {
    Annotation[] value();
}

Но это приводит к ошибке компилятора "недопустимый тип для элемента аннотации".

Объект [] также не работает.

Есть ли способ сделать то, что я хочу?

Ответ 1

Я сам предлагаю обходной путь для данной проблемы:

Ну, я хотел сделать что-то вроде этого:

@Contract({
    @ExclusiveOr({
        @IsType(IAtomicType.class),
        @Or({
            @IsType(IListType.class),
            @IsType(ISetType.class)
        })
    })
})

Предлагаемое обходное решение:

Определите класс с конструктором без параметров (который позже будет вызываться вашим собственным обработчиком аннотаций) следующим образом:

final class MyContract extends Contract{
    // parameter-less ctor will be handeled by annotation processor
    public MyContract(){
        super(
            new ExclusiveOr(
                new IsType(IAtomicType.class),
                new Or(
                    new IsType(IListType.class),
                    new IsType(ISetType.class)
                )
            )
        );
    }
}

использование:

@Contract(MyContract.class)
class MyClass{
    // ...
}

Ответ 2

Ошибка возникает из-за того, что вы не можете использовать интерфейсы в качестве значений аннотации (измените их на Comparable, и вы получите ту же ошибку). Из JLS:

Это ошибка времени компиляции, если возвращаемый тип метода, объявленного в типе аннотации, представляет собой любой тип, отличный от одного из следующих: один из примитивных типов String, Class и любое обращение Class, тип перечисления, тип аннотации или массив одного из предыдущих типов. Это также ошибка времени компиляции, если какой-либо метод, объявленный в типе аннотации, имеет подпись, переопределяющую эквивалентную для любого метода public или protected, объявленного в классе Object или в интерфейсе annotation.Annotation.

Я боюсь, что не знаю об этом, но теперь, по крайней мере, вы знаете, почему вы получаете ошибку.

Ответ 3

Вы можете сделать:

Class<? extends Annotation>[] value();

Не уверен, что это помогает, но.,

Ответ 4

В зависимости от причины, по которой вы хотите указать другие аннотации, существует несколько решений:

Массив экземпляров одного типа аннотации

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

public @interface Test {
    SomeAnnotation[] value();
}

Массив типов аннотаций вместо экземпляров

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

public @interface Test {
    Class<? extends Annotation>[] value();
}

Но перечисление, конечно же, также будет делать трюк в большинстве ситуаций.

Использовать несколько массивов

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

public @interface Test {
    SomeAnnotation[] somes() default { };
    ThisAnnotation[] thiss() default { };
    ThatAnnotation[] thats() default { };
}

Предоставление значения по умолчанию каждому члену позволяет указывать только массивы для типов, которые вам нужны.

Ответ 5

Я просто столкнулся с этой точной проблемой, но (вдохновленный @ivan_ivanovich_ivanoff). Я обнаружил способ указать набор любой комбинации аннотаций в качестве члена аннотации: используйте класс prototype/template.

В этом примере я определяю WhereOr (т.е. предложение "where" для моей аннотации модели), которое мне нужно содержать произвольные мета-аннотации Spring (например, мета-аннотации @Qualifier).

Недостаток (?) в этом случае является принудительным разыменованием, которое отделяет реализацию предложения where с конкретным типом, который он описывает.

@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface WhereOr {
    Class<?>[] value() default {};
}

@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonModel {
    Class<?> value();
    WhereOr where() default @WhereOr;
}

public class Prototypes {
    @Qualifier("myContext")
    @PreAuthorize("hasRole('ROLE_ADMINISTRATOR')")
    public static class ExampleAnd {
    }
}

@JsonModel(
        value = MusicLibrary.class,
        where = @WhereOr(Prototypes.ExampleAnd.class)
)
public interface JsonMusicLibrary {
    @JsonIgnore
    int getMajorVersion();
    // ...
}

Я программно извлечу возможные допустимые конфигурации из аннотации "where clause". В этом случае я также использую класс prototypes как логическую группировку AND и массив классов как логический OR.