替换 METHOD/FIELD/etc 的兼容性风险是什么? TYPE_USE 的目标

What are the compatibility risks of replacing METHOD/FIELD/etc. targets with TYPE_USE

我有一个 Java 包,其中包含外部客户端使用的注释。该包出现在 Java 8 之前,因此历史上这些注释的目标是 ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE。现在这个包至少需要 Java 8 个版本。从语义上讲,包中的注释适用于类型,例如注释方法时,注释有效地应用于方法 return 类型。现在客户也想注释泛型类型参数(例如 List<@MyAnnotation String>)。由于我们放弃了对 Java 7 及以下版本的支持,因此将注释目标设置为 ElementType.TYPE_USE 似乎很自然,并且为了减少歧义,删除现有目标。

这里的问题是:将 ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE 目标替换为 TYPE_USE 时,现有客户端是否存在兼容性风险?现有代码是否有可能停止编译?二进制兼容性怎么样?如果在运行时将更改前编译的 class-文件与较新的注释包一起使用,是否会导致任何运行时问题?

注释的保留政策是 CLASS 如果这很重要。

在此更改期间可能会出现许多源兼容性问题:

  • void return 类型的方法无法再进行注释。 @MyAnnotation void method() {} 可以用 ElementType.METHOD 目标编译,但不能用 TYPE_USE 目标编译。
  • 当在源代码中使用限定类型时,TYPE_USE 注释必须出现在限定符之后。例如。 void method(@MyAnnotation OuterClass.InnerClass param) {} 是具有 ElementType.PARAMETER 目标的有效代码,但在更改为 TYPE_USE.
  • 后应更新为 void method(OuterClass.@MyAnnotation InnerClass param) {}
  • 应用于数组的注释将具有不同的含义。例如。在迁移 @MyAnnotation String[] getData(); 注释方法 getData 之前,注释客户端可能假设注释应用于 return 类型(字符串数组)。迁移后,相同的代码意味着注解应用于数组组件(字符串)。这可能会导致行为改变,具体取决于注释语义以及客户端如何处理它。为了保留含义,客户应将此类代码更新为 String @MyAnnotation [] getData();.
  • 这样的改变使得 Kotlin 代码中所有注解的使用都无效。在 Kotlin 中,TYPE_USE 注释与其他注释在语法上存在严格的区别。例如。 PARAMETER 注释必须用作 fun(@MyAnnotation param : String) {...}。这对于 TYPE_USE 注释是不正确的,它必须用作 fun(param : @MyAnnotation String) {...}。如果您的客户使用 Kotlin,他们将不得不修复每一个注解的使用。
  • 这样的更改不允许在 Groovy 代码中使用您的注释。目前,正如 Groovy documentation 所说,Groovy 不支持 TYPE_PARAMETER 和 TYPE_USE 元素类型,它们在 Java 8 中引入。如果您的客户使用 Groovy 他们将无法再使用您的注释包。

虽然在运行时应该不会出现问题。由于注解的保留策略是 CLASS(而不是 RUNTIME),而 class 文件中的注解会被运行时忽略。根本没有必要将注释包添加到 class 路径。