包含其他注释的注释成员?

时间:2022-09-25 10:36:25

I want to create a custom annotation (using Java) which would accept other annotations as parameter, something like:

我想创建一个自定义注释(使用Java),它将接受其他注释作为参数,如:

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

But this causes compiler error "invalid type for annotation member".

但这会导致编译器错误“注释成员的无效类型”。

Object[] also doesn't work.

对象[]也不起作用。

Is there a way to do what I want?

有办法做我想要的吗?

5 个解决方案

#1


5  

The error is produced because you can't use interfaces as annotation values (change it to Comparable and you'll get the same error). From the JLS:

产生错误是因为您不能将接口用作注释值(将其更改为Comparable并且您将获得相同的错误)。来自JLS:

It is a compile-time error if the return type of a method declared in an annotation type is any type other than one of the following: one of the primitive types, String, Class and any invocation of Class, an enum type, an annotation type, or an array of one of the preceding types. It is also a compile-time error if any method declared in an annotation type has a signature that is override-equivalent to that of any public or protected method declared in class Object or in the interface annotation.Annotation.

如果在注释类型中声明的方法的返回类型是除以下之一之外的任何类型,则是编译时错误:其中一种基本类型,String,Class和Class的任何调用,枚举类型,注释类型,或前面类型之一的数组。如果在注释类型中声明的任何方法具有覆盖等同于在类Object或接口annotation.Annotation中声明的任何公共或受保护方法的签名,则它也是编译时错误。

I'm afraid I don't know of a good workaround, but now at least you know why you get the error.

我担心我不知道一个好的解决方法,但现在至少你知道为什么你会得到错误。

#2


2  

I myself hereby propose a workaround for the given problem:

我自己特此提出针对给定问题的解决方法:

Well, what I wanted to make possible was something like that:

好吧,我想让它成为可能的是这样的:

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

Proposed workaround:

Define a class with parameter-less constructor (which will be called by your own annotation processor later) in following way:

使用无参数构造函数(稍后将由您自己的注释处理器调用)以下列方式定义一个类:

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)
                )
            )
        );
    }
}

usage:

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

#3


2  

Depending on the reason why you would want to specify other annotations there are multiple solutions:

根据您希望指定其他注释的原因,有多种解决方案:

An array of instances of a single annotation type

Probably not what you meant in your question, but if you want to specify multiple instances of a single annotation type it's certainly possible:

可能不是你在你的问题中的意思,但如果你想指定单个注释类型的多个实例,它肯定是可能的:

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

An array of annotation types instead of instances

If you do not need to specify any parameters on the individual annotations you can just user their class objects instead of instances.

如果您不需要在单个注释上指定任何参数,则只需使用其类对象而不是实例。

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

But an enum would of course also do the trick in most situations.

但是在大多数情况下,枚举当然也会成功。

Use multiple arrays

If the set of possible annotation types you want to use is limited, you can create a separate parameter for each one.

如果要使用的可能注释类型集受限,则可以为每个注释类型创建单独的参数。

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

Giving a default value to each member makes it possible to only specify arrays for the types you need.

为每个成员提供默认值使得只能为所需类型指定数组。

#4


1  

You can do:

你可以做:

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

Not sure if that helps, but . . .

不确定这是否有帮助,但是。 。 。

#5


0  

I just ran into this exact problem, but (inspired by @ivan_ivanovich_ivanoff) I have discovered a way to specify a bundle of any combination of Annotations as an annotation member: use a prototype / template class.

我刚刚遇到了这个确切的问题,但是(受@ivan_ivanovich_ivanoff启发)我发现了一种方法来指定任何Annotations组合作为注释成员的包:使用原型/模板类。

In this example I define a WhereOr (i.e. a "where clause" for my model annotation) which I need to contain arbitrary Spring meta-annotations (like @Qualifier meta-annotations).

在这个例子中,我定义了一个WhereOr(即我的模型注释的“where子句”),我需要包含任意Spring元注释(如@Qualifier元注释)。

The minor (?) defect in this is the forced dereferencing that separates the implementation of the where clause with the concrete type that it describes.

这里的次要(?)缺陷是强制解除引用,它将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();
    // ...
}

I will programmatically extract the possible valid configurations from the "where clause" annotation. In this case I also use the prototypes class as a logical AND grouping and the array of classes as the logical OR.

我将以编程方式从“where子句”注释中提取可能的有效配置。在这种情况下,我还使用prototypes类作为逻辑AND分组,并将类数组用作逻辑OR。

#1


5  

The error is produced because you can't use interfaces as annotation values (change it to Comparable and you'll get the same error). From the JLS:

产生错误是因为您不能将接口用作注释值(将其更改为Comparable并且您将获得相同的错误)。来自JLS:

It is a compile-time error if the return type of a method declared in an annotation type is any type other than one of the following: one of the primitive types, String, Class and any invocation of Class, an enum type, an annotation type, or an array of one of the preceding types. It is also a compile-time error if any method declared in an annotation type has a signature that is override-equivalent to that of any public or protected method declared in class Object or in the interface annotation.Annotation.

如果在注释类型中声明的方法的返回类型是除以下之一之外的任何类型,则是编译时错误:其中一种基本类型,String,Class和Class的任何调用,枚举类型,注释类型,或前面类型之一的数组。如果在注释类型中声明的任何方法具有覆盖等同于在类Object或接口annotation.Annotation中声明的任何公共或受保护方法的签名,则它也是编译时错误。

I'm afraid I don't know of a good workaround, but now at least you know why you get the error.

我担心我不知道一个好的解决方法,但现在至少你知道为什么你会得到错误。

#2


2  

I myself hereby propose a workaround for the given problem:

我自己特此提出针对给定问题的解决方法:

Well, what I wanted to make possible was something like that:

好吧,我想让它成为可能的是这样的:

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

Proposed workaround:

Define a class with parameter-less constructor (which will be called by your own annotation processor later) in following way:

使用无参数构造函数(稍后将由您自己的注释处理器调用)以下列方式定义一个类:

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)
                )
            )
        );
    }
}

usage:

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

#3


2  

Depending on the reason why you would want to specify other annotations there are multiple solutions:

根据您希望指定其他注释的原因,有多种解决方案:

An array of instances of a single annotation type

Probably not what you meant in your question, but if you want to specify multiple instances of a single annotation type it's certainly possible:

可能不是你在你的问题中的意思,但如果你想指定单个注释类型的多个实例,它肯定是可能的:

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

An array of annotation types instead of instances

If you do not need to specify any parameters on the individual annotations you can just user their class objects instead of instances.

如果您不需要在单个注释上指定任何参数,则只需使用其类对象而不是实例。

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

But an enum would of course also do the trick in most situations.

但是在大多数情况下,枚举当然也会成功。

Use multiple arrays

If the set of possible annotation types you want to use is limited, you can create a separate parameter for each one.

如果要使用的可能注释类型集受限,则可以为每个注释类型创建单独的参数。

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

Giving a default value to each member makes it possible to only specify arrays for the types you need.

为每个成员提供默认值使得只能为所需类型指定数组。

#4


1  

You can do:

你可以做:

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

Not sure if that helps, but . . .

不确定这是否有帮助,但是。 。 。

#5


0  

I just ran into this exact problem, but (inspired by @ivan_ivanovich_ivanoff) I have discovered a way to specify a bundle of any combination of Annotations as an annotation member: use a prototype / template class.

我刚刚遇到了这个确切的问题,但是(受@ivan_ivanovich_ivanoff启发)我发现了一种方法来指定任何Annotations组合作为注释成员的包:使用原型/模板类。

In this example I define a WhereOr (i.e. a "where clause" for my model annotation) which I need to contain arbitrary Spring meta-annotations (like @Qualifier meta-annotations).

在这个例子中,我定义了一个WhereOr(即我的模型注释的“where子句”),我需要包含任意Spring元注释(如@Qualifier元注释)。

The minor (?) defect in this is the forced dereferencing that separates the implementation of the where clause with the concrete type that it describes.

这里的次要(?)缺陷是强制解除引用,它将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();
    // ...
}

I will programmatically extract the possible valid configurations from the "where clause" annotation. In this case I also use the prototypes class as a logical AND grouping and the array of classes as the logical OR.

我将以编程方式从“where子句”注释中提取可能的有效配置。在这种情况下,我还使用prototypes类作为逻辑AND分组,并将类数组用作逻辑OR。