Член аннотации, который содержит другие аннотации? - PullRequest
7 голосов
/ 24 марта 2009

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

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

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

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

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

Ответы [ 5 ]

5 голосов
/ 24 марта 2009

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

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

Боюсь, я не знаю хорошего обходного пути, но теперь, по крайней мере, вы знаете, почему вы получаете ошибку.

2 голосов
/ 18 марта 2013

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

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

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

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

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

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

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

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

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

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

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

Задание значения по умолчанию для каждого члена позволяет указывать массивы только для нужных вам типов.

2 голосов
/ 25 марта 2009

Я сам предлагаю обойти эту проблему:

Ну, я хотел сделать что-то подобное:

@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{
    // ...
}
1 голос
/ 24 марта 2009

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

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

Не уверен, поможет ли это, но. , ,

0 голосов
/ 09 июля 2014

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

В этом примере я определяю 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. В этом случае я также использую класс прототипов в качестве логической группы И и массив классов в качестве логического ИЛИ.

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