替换 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 路径。
我有一个 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
. 后应更新为 - 应用于数组的注释将具有不同的含义。例如。在迁移
@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 他们将无法再使用您的注释包。
void method(OuterClass.@MyAnnotation InnerClass param) {}
虽然在运行时应该不会出现问题。由于注解的保留策略是 CLASS
(而不是 RUNTIME
),而 class 文件中的注解会被运行时忽略。根本没有必要将注释包添加到 class 路径。