我试图在一个元素上拍两个或多个相同类型的注释,在本例中是一个方法。这是我正在使用的近似代码:
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: duplicate annotation
根本不可能重复这样的注释吗?从小学的角度讲,由于内容不同,@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这样做并且它不被认为是黑客攻击,我认为至少允许在一个元素上具有相同类型的多个注释仍然是有意义的。
答案 0 :(得分:131)
不允许使用两个或多个相同类型的注释。但是,您可以这样做:
public @interface Foos {
Foo[] value();
}
@Foos({@Foo(bar="one"), @Foo(bar="two")})
public void haha() {}
您需要在代码中专门处理Foos注释。
顺便说一下,我刚刚用这个问题解决了同样的问题:)
答案 1 :(得分:58)
在Java 8(2014年3月发布)中,可以编写重复/重复注释。请参阅http://docs.oracle.com/javase/tutorial/java/annotations/repeating.html。
答案 2 :(得分:14)
http://docs.oracle.com/javase/tutorial/java/annotations/repeating.html
从Java8开始,您可以描述可重复的注释:
@Repeatable(FooValues.class)
public @interface Foo {
String bar();
}
public @interface FooValues {
Foo[] value();
}
注意,value
是值列表的必填字段。
现在你可以使用注释重复它们而不是填充数组:
@Foo(bar="one")
@Foo(bar="two")
public void haha() {}
答案 3 :(得分:12)
正如sfussenegger所说,这是不可能的。
通常的解决方案是构建一个“多个”注释,它处理前一个注释的数组。它的名称通常相同,后缀为's'。
顺便说一句,这在大型公共项目(例如Hibernate)中非常常用,所以它不应该被视为黑客攻击,而是一种正确的解决方案来满足这种需求。
根据您的需要,允许您的早期注释处理多个值可能会更好。
示例:
public @interface Foo {
String[] bars();
}
答案 4 :(得分:12)
除了提到的其他方法之外,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(value = [@ com.Foo(value = 1),@ com.Foo(value = 2), @ com.Foo(value = 3)])
@ com.FooContainer(value = [@ com.Foo(value = 1),@ com.Foo(value = 2),@ com.Foo(value = 3)])
答案 5 :(得分:4)
将其他答案组合成最简单的形式......带有简单值列表的注释......
@Foos({"one","two"})
private String awk;
//...
public @interface Foos{
String[] value();
}
答案 6 :(得分:3)
如果您只有一个参数“bar”,则可以将其命名为“value”。在这种情况下,当您像这样使用它时,您根本不必编写参数名称:
@Foos({@Foo("one"), @Foo("two")})
public void haha() {}
有点短,整洁,imho ..
答案 7 :(得分:0)
在Java的当前版本中,我可以使用以下注释解决此问题:
@Foo({"one", "two"})