【问题标题】:Multiple annotations of the same type on one element?一个元素上有多个相同类型的注释?
【发布时间】:2022-01-03 18:25:17
【问题描述】:

我试图在单个元素上添加两个或多个相同类型的注释,在本例中是一个方法。这是我正在使用的大致代码:

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 做到了这一点并且它不被视为 hack,但我认为至少允许在单个元素上具有多个相同类型的注释仍然是有意义的。

【问题讨论】:

  • 正在努力放宽这个重复规则,以允许您的程序使用 Java 7。请描述一下您的用例吗?
  • 我已经编辑了我的问题,并说明了我为什么要这样做。谢谢。
  • 在 CDI 中允许为多个限定符提供一个 bean 可能很方便。例如,我刚刚尝试通过限定它在两个地方重用 bean "@Produces @PackageName("test1") @PackageName("test2")"
  • 进一步:下面的答案并不能解决这个问题,因为 CDI 会将复合材料视为一个限定符。
  • @MaxA。请将您的“绿色支票”接受更改为 the correct Answer by mernst。 Java 8 增加了重复注解的能力。

标签: java annotations


【解决方案1】:

注意:由于 Java 8 引入了 @Repeatable 注释,此答案已部分过时(请参阅 @mernst 的答案)。但仍然需要@Foos 容器注释和专用处理。

不允许使用两个或多个相同类型的注释。但是,您可以这样做:

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

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

// post Java 8 with @Repeatable(Foos.class) on @Foo
@Foo(bar="one") @Foo(bar="two")
public void haha() {}

您需要专门处理代码中的 Foos 注释。

【讨论】:

  • 你也可以在 Groovy 中这样做吗?
  • @Excel20 是的。但是,您必须使用方括号,例如@Foos([@Foo(bar="one"), @Foo(bar="two")])。见groovy.codehaus.org/Annotations+with+Groovy
  • 今天有点晚了,但是要指出可以在 Foos 中处理 Foo 列表的建议?目前我正在尝试处理方法的结果,但尽管 Foos 被拦截,但 Foo 建议从未输入
  • 更新: 从 Java 8 开始,此答案已过时。请参阅 mernst 的the correct modern Answer。 Java 8 增加了重复注解的能力。
  • 是否可以将“@Foo”值添加为常量?或者你如何访问每一个?我尝试使用类似“@StringDef”的东西并从另一个定义一个“@interface”。
【解决方案2】:

Java 8 中的重复注解

Java 8(2014 年 3 月发布)中,可以编写重复/重复的注解。

参见教程,Repeating Annotations

请参阅规范,JEP 120: Repeating Annotations

【解决方案3】:

除了提到的其他方式之外,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)])

【讨论】:

  • 值得指出的是,FooContainer 中的方法/字段名称必须严格命名为“value()”。否则 Foo 将无法编译。
  • ...也包含注解类型 (FooContainer) 不能适用于比可重复注解类型 (Foo) 更多的类型。
【解决方案4】:

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() {}

【讨论】:

    【解决方案5】:

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

    通常的解决方案是构建一个“多个”注解,它处理前一个注解的数组。它通常命名相同,带有“s”后缀。

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


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

    例子:

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

    【讨论】:

    • 我知道这非常熟悉。谢谢你刷新我的记忆。
    • 现在可以使用 Java 8。
    【解决方案6】:

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

    @Foos({"one","two"})
    private String awk;
    
    //...
    
    public @interface Foos{
        String[] value();
    }
    

    【讨论】:

      【解决方案7】:

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

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

      有点短和整洁,恕我直言..

      【讨论】:

      • 正确的观点,但这如何尝试回答 OP 的问题?
      • @MouseEvent 你是对的,我认为这更多的是对 sfussenegger 最佳答案的改进,因此更多地属于那里的 cmets。但是由于可重复的注释,答案无论如何都已经过时了......
      【解决方案8】:

      在当前版本的 Java 中,我能够通过以下注释解决此问题:

      @Foo({"one", "two"})
      

      【讨论】:

      • 哪个版本? jdk 8,9,10,11?
      猜你喜欢
      • 2023-02-04
      • 2017-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-25
      • 1970-01-01
      相关资源
      最近更新 更多