Java类型检查器注解的@Retention

5
Java 8的类型注解(JSR 308)允许类型检查器进行静态代码分析。例如,The Checker Framework可以通过@NonNull注解检查可能的nullness
各种项目定义自己的NonNull注解,例如:
  • org.checkerframework.checker.nullness.qual.NonNull
  • edu.umd.cs.findbugs.annotations.NonNull
  • javax.annotation.Nonnull
  • javax.validation.constraints.NotNull
  • lombok.NonNull
  • org.eclipse.jdt.annotation.NonNull
  • 等(参见The Checker Framework Manual, section 3.7
对于这样的注解,我希望@interface应该有@Retention(RetentionPolicy.CLASS),因为它们通常不需要在运行时使用。最重要的是,代码没有任何与相应库的运行时依赖关系。

虽然org.eclipse.jdt.annotation.NonNull采用了这种方法,但大多数其他NonNull注解,例如javax.annotation.Nonnull(JSR 305)和org.checkerframework.checker.nullness.qual.NonNull本身,都有@Retention(RetentionPolicy.RUNTIME)。这些注解中的RetentionPolicy.RUNTIME是否有特定的原因?


澄清:Checker框架支持在注释中使用的注解以实现向后兼容。然而,仅为了避免运行时依赖而在Java 8中使用这些注解似乎是一种不好的hack方法。
2个回答

7

这是一个很好的问题。

为了在编译时进行静态检查,保留CLASS即可。需要注意的是,SOURCE不够用,因为需要分离编译:当对类进行类型检查时,编译器需要读取使用的库中的注解,而分离编译的库只以类文件的形式提供给编译器。

注解设计者使用RUNTIME保留,以允许工具执行运行时操作。这可能包括检查注解(类似于assert语句)、动态加载代码的类型检查、强制转换和instanceof操作的检查、更精确地解析反射等。目前没有太多这样的工具,但注解设计者希望未来能够适应它们。

您提到使用@Retention(RetentionPolicy.CLASS),"代码在相应库上没有任何运行时依赖。" 实际上,@Retention(RetentionPolicy.RUNTIME)也是如此!请参阅此Stack Overflow问题:为什么缺少注解不会在运行时导致ClassNotFoundException?

总之,使用CLASS保留在运行时消耗的空间很少,为未来提供了更多的潜在用途,并且不会引入运行时依赖。

在Checker Framework的情况下,它提供运行时测试,例如isRegex(String)。如果您的代码使用这些方法,则您的代码将依赖于Checker Framework运行时库(该库比整个Checker Framework本身小,并具有更宽松的许可证)。


关于使用Mockito(版本2.2.0)模拟注解类的相关说明:虽然RetentionPolicy.RUNTIME表示二进制中存在的注解在运行时不需要可用,但https://bugs.openjdk.java.net/browse/JDK-8152174在Java 8中模拟一个有注解的类且该注解在类路径上不可用时会导致NullPointerException。 - MyKey_

1
每个注释都有它的用途!
javax.validation.constraints.NotNull

这个是由Bean验证规范定义的,用于在运行时执行非空检查,因此需要在运行时保留以执行例如表单验证等操作...
@RetentionPolicy.SOURCE =>通常用于文档 @RetentionPocily.CLASS =>允许向编译器提供一些信息,但不允许向JVM提供(例如,在编译期间执行代码生成) @RetentionPolicy.RUNTIME => 允许在JVM级别检索注释信息(因此在运行时)。
问候,
Loïc

是的, javax.validation.constraints.NotNull 有运行时目的。但是,在我看来, javax.annotation.Nonnullorg.checkerframework.checker.nullness.qual.NonNull 没有运行时目的。 - MyKey_
1
对于你的问题,没有一个全局性的答案,这取决于注解的创建者是否需要在运行时保留它。可以参考此SOW帖子获取一些提示:https://dev59.com/smUq5IYBdhLWcg3wEcbu - loicmathieu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接