一个元素上有多个相同类型的注释?


88

我试图在一个元素上拍两个或多个相同类型的注释,在这种情况下是方法。这是我正在使用的近似代码:

public class Dupe {
    public @interface Foo {
      String bar();
    }

    @Foo(bar="one")
    @Foo(bar="two")
    public void haha() {}
}

编译以上内容时,javac抱怨重复的注释:

max @ upsight:〜/ work / daybreak $ javac Dupe.java 
Dupe.java:5:重复注释

这样根本不可能重复注释吗?从学步上讲,上面的两个@Foo实例是否由于内容不同而不同吗?

如果上述方法不可行,可能有哪些解决方法?

更新:我被要求描述我的用例。开始。

我正在建立一种语法糖化机制,以“映射” POJO到文档存储(例如MongoDB)。我想允许将索引指定为getter或setter上的注释。这是一个人为的例子:

public class Employee {
    private List<Project> projects;

    @Index(expr = "project.client_id")
    @Index(expr = "project.start_date")
    public List<Project> getProjects() { return projects; }
}

显然,我希望能够通过Project的各种属性快速找到Employee的实例。我可以使用不同的expr()值指定两次@Index,或者采用接受的答案中指定的方法。即使Hibernate这样做并且不被认为是黑客,我认为至少允许在单个元素上具有相同类型的多个注释仍然有意义。


1
我们正在努力放松此重复规则,以允许您的Java 7程序运行。您能描述一下用例吗?
notnoop

我已经编辑了我的问题,并描述了为什么要这样做。谢谢。
Max A.

在CDI中方便地允许为多个限定符提供bean。例如,我刚刚尝试通过在两个位置重用一个bean,将其限定为“ @Produces @PackageName(“ test1”)@PackageName(“ test2”)”
Richard

此外:下面的答案不能解决该问题,因为CDI会将复合材料视为一个限定符。
理查德·科菲尔德

Answers:


139

不允许两个或多个相同类型的注释。但是,您可以执行以下操作:

public @interface Foos {
    Foo[] value();
}

@Foos({@Foo(bar="one"), @Foo(bar="two")})
public void haha() {}

但是,您将需要对代码中的Foos批注进行专门处理。

顺便说一句,我刚刚在2小时前使用过此方法来解决同一问题:)


2
您还可以在Groovy中这样做吗?
Excel20 2012年

5
@ Excel20是的。不过,您必须使用方括号,例如@Foos([@Foo(bar="one"), @Foo(bar="two")])。参见groovy.codehaus.org/Annotations+with+Groovy
sfussenegger 2012年

有点迟了,但是要指出可以在Foos中处理Foo列表的建议吗?目前,我正在尝试处理方法的结果,但是尽管Foos被拦截,但Foo的建议从未输入
Stelios Koussouris


20

除了上面提到的其他方法外,Java8还有一种更简单的方法:

@Target(ElementType.TYPE)
@Repeatable(FooContainer.class)
@Retention(RetentionPolicy.RUNTIME)
@interface Foo {
    String value();

}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface FooContainer {
        Foo[] value();
        }

@Foo("1") @Foo("2") @Foo("3")
class Example{

}

默认情况下获取示例FooContainer作为注释

    Arrays.stream(Example.class.getDeclaredAnnotations()).forEach(System.out::println);
    System.out.println(Example.class.getAnnotation(FooContainer.class));

以上两种打印:

@ com.FooContainer(值= [@@ com.Foo(值= 1),@ com.Foo(值= 2),@ com.Foo(值= 3)])

@ com.FooContainer(值= [@@ com.Foo(值= 1),@ com.Foo(值= 2),@ com.Foo(值= 3)])


值得指出的是,FooContainer中的方法/字段名称必须严格命名为“ value()”。否则,Foo将无法编译。
Tomasz Mularczyk

...还包含注释类型(FooContainer)的类型不能超过可重复注释类型(Foo)的更多类型。
Tomasz Mularczyk '16


12

正如sfussenegger所说,这是不可能的。

通常的解决方案是构建“多个”注释,该注释处理先前注释的数组。通常以相同的名称命名,后缀为“ s”。

顺便说一句,这在大型公共项目(例如Hibernate)中非常常用,因此不应将其视为黑客,而应将其视为满足此需求的正确解决方案。


根据您的需求,最好允许您先前的注释处理多个值

例:

    public @interface Foo {
      String[] bars();
    }

我知道这是非常熟悉的。感谢您刷新我的记忆。
Max A.

Java 8现在可以实现
。– Anis

4

将其他答案组合成最简单的形式...带有简单值列表的注释...

@Foos({"one","two"})
private String awk;

//...

public @interface Foos{
    String[] value();
}

3

如果只有1个参数“ bar”,则可以将其命名为“ value”。在这种情况下,像这样使用时,您根本不必写参数名:

@Foos({@Foo("one"), @Foo("two")})
public void haha() {}

一点点,更整洁,恕我直言..


正确点,但是这如何尝试回答OP的问题?
Mordechai

@MouseEvent你是对的,我认为这更多是对sfussenegger的最佳答案的改进,因此更多地属于那里的评论。但是由于重复的注释,答案还是过时了……
golwig

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.