替换 METHOD/FIELD/etc 有哪些兼容性风险?TYPE_USE 的目标

Tag*_*eev 5 java compatibility annotations java-8

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

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

注释的保留政策是CLASS这是否重要。

Tag*_*eev 6

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

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

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