【问题标题】:@Retention of Java type checker annotations@Retention Java 类型检查器注解
【发布时间】:2016-12-22 20:08:00
【问题描述】:

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 框架支持 cmets 中的注释以实现向后兼容性。然而,在 Java 8 中使用那些只是为了避免运行时依赖似乎是一种肮脏的 hack。

【问题讨论】:

    标签: java annotations retention checker-framework


    【解决方案1】:

    这是个好问题。

    为了在编译时进行静态检查,CLASS 保留就足够了。请注意,SOURCE 保留是不够的,因为单独编译:当对类进行类型检查时,编译器需要读取它使用的库上的注释,并且单独编译的库只能作为类文件提供给编译器.

    注释设计者使用RUNTIME 保留来允许工具执行运行时操作。这可能包括检查注释(如断言语句)、动态加载代码的类型检查、强制转换检查和instanceof 操作、更精确地解析反射等等。今天这样的工具并不多,但注释设计者希望在未来适应它们。

    您用@Retention(RetentionPolicy.CLASS) 评论说,“代码对各自的库没有任何运行时依赖项。” @Retention(RetentionPolicy.RUNTIME) 也是如此!请参阅此堆栈溢出问题: Why doesn't a missing annotation cause a ClassNotFoundException at runtime?.

    总之,使用CLASS 保留在运行时花费的空间可以忽略不计,可以在未来实现更多潜在用途,并且不会引入运行时依赖性。

    对于 Checker Framework,它提供运行时测试,例如 isRegex(String)。如果您的代码使用此类方法,您的代码将依赖于 Checker Framework 运行时库(它比整个 Checker Framework 本身小,并且具有更宽松的许可证)。

    【讨论】:

    • 使用 mockito 模拟带注释的类的相关说明(版本 2.2.0):虽然 RetentionPolicy.RUNTIME 意味着二进制文件中存在的注释不必在运行时可用,bugs.openjdk.java.net/browse/JDK-8152174 会导致Java 8 中的 NullPointerException 在模拟类路径上的注释不可用的注释类时。
    【解决方案2】:

    每个注释都有它的用途!

    javax.validation.constraints.NotNull
    

    这个是由bean验证规范定义的,用于在运行时进行非空检查,所以需要在运行时保留它来执行,例如表单验证...

    @RetentionPolicy.SOURCE => 通常用于文档 @RetentionPocily.CLASS => 允许向编译器提供一些信息,而不是向 JVM 提供一些信息(例如,在编译期间执行代码生成) @RetentionPolicy.RUNTIME => 允许在 JVM 级别检索注解信息(因此在运行时)。

    问候,

    洛伊克

    【讨论】:

    • 是的 javax.validation.constraints.NotNull 具有运行时目的。但是 javax.annotation.Nonnullorg.checkerframework.checker.nullness.qual.NonNull 没有运行时目的 IMO。
    • 您的问题没有全局答案,由注释的创建者定义是否需要在运行时保留。请参阅此 SOW 线程以获取一些提示:stackoverflow.com/questions/14810030/…
    猜你喜欢
    • 2011-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多