Участник аннотации, который содержит другие аннотации?
Я хочу создать пользовательскую аннотацию (используя 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.