43

假设我有一个带有属性的注释:

@Named(name = "Steve")
private Person person

我想用几个元注释创建一个复合注释,包括一个带有属性的注释

@Named
@AnotherAnnotation
@YetAnotherAnnotation
public @interface CompoundAnnotation {

    ...
}

有没有一种方法可以将复合注释的属性传递给元注释之一?

例如,像这样:

@CompoundAnnotation(name = "Bob")
private Person person;

这相当于,但比

@Named(name = "Bob")
@AnotherAnnotation
@YetAnotherAnnotation
private Person person;

谢谢!

PS 为我对示例注释的错误选择表示歉意 - 我没有想到 javax.inject.@Named 注释,只是一些具有属性的任意注释。


谢谢大家的回答/评论。

显然,这是不可能的。然而,碰巧我的案例有一个简单的解决方法,我将分享它以防它帮助任何人:

我正在使用 Spring 并希望创建自己的注释,将 @Component 作为元注释,从而被组件扫描自动检测到。但是,我还希望能够设置 BeanName 属性(对应于 @Component 中的 value 属性),这样我就可以拥有自定义 bean 名称。

好吧,事实证明,Spring 的深思熟虑的人使这样做成为可能 - AnnotationBeanNameGenerator 将采用它传递的任何注释的“值”属性并将其用作 bean 名称(当然,默认情况下,它会仅获得传递的 @Component 或将 @Component 作为元注释的注释)。回想起来,这对我来说从一开始就应该是显而易见的——这就是现有的以@Component 作为元注释的注释,例如@Service 和@Registry,可以提供 bean 名称。

希望这对某人有用。我仍然认为这是一种耻辱,虽然这不可能更普遍!

4

2 回答 2

53

现在是几年后了,由于您使用的是 Spring,因此您现在可以使用 @AliasFor 注释来实现您的要求。

例如:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@SpringApplicationConfiguration
@ActiveProfiles("test")
public @interface SpringContextTest {

    @AliasFor(annotation = SpringApplicationConfiguration.class, attribute = "classes")
    Class<?>[] value() default {};

    @AliasFor("value")
    Class<?>[] classes() default {};
}

现在您可以使用 注释您的测试@SpringContextTest(MyConfig.class),令人惊奇的是它实际上以您期望的方式工作。

注意当您需要以编程方式获取属性值时,Spring 自动别名仅在您使用AnnotatedElementUtils而不是时才有效AnnotationUtils,如文档所述:

AnnotatedElementUtils为 Spring 的元注释编程模型定义公共 API,支持注释属性覆盖。如果您不需要对注释属性覆盖的支持,请考虑AnnotationUtils改用。

例子:

final Named namedAnnotation = AnnotatedElementUtils.findMergedAnnotation(Person.class, Named.class);
final String name = namedAnnotation.name();
assertEquals("Steve", name);
于 2016-04-10T09:08:52.297 回答
10

有没有一种方法可以将复合注释的属性传递给元注释之一?

我认为简单的答案是“不”。没有办法询问Person它上面有什么注释并得到@Named例如。

更复杂的答案是您可以链接注释,但您必须通过反射来调查这些注释。例如,以下工作:

@Bar
public class Foo {
    public static void main(String[] args) {
        Annotation[] fooAnnotations = Foo.class.getAnnotations();
        assertEquals(1, fooAnnotations.length);
        for (Annotation annotation : fooAnnotations) {
            Annotation[] annotations =
                annotation.annotationType().getAnnotations();
            assertEquals(2, annotations.length);
            assertEquals(Baz.class, annotations[0].annotationType());
        }
    }

    @Baz
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Bar {
    }

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Baz {
    }
}

但是,以下语句将返回 null:

// this always returns null
Baz baz = Foo.class.getAnnotation(Baz.class)

这意味着任何正在寻找@Baz注释的第 3 方类都不会看到它。

于 2012-04-10T12:40:52.280 回答