@SafeVarargs和Java 6的互操作性

Luk*_*der 7 java variadic-functions suppress-warnings java-6 java-7

我的API中有一个带有通用varargs参数的方法.我希望我的API是Java 6源代码和二进制兼容的,但如果Java 7 API消费者不会遭受不必要的"varargs"警告,那将会很好.

我能想到的一个技巧是将我自己的java.lang.SafeVarargs注释添加到我的API并将其与我的可交付成果一起发送.效果如下:

  • Java 6编译器无法识别此注释,只是忽略它.
  • Java 7编译器会识别这个注释,并且可能(?)首先从JDK类加载一个,因此它们不会再产生烦人的警告.

除了许可证问题,这是否可以保证有效?它似乎与javac一起使用.或者是否存在从JDK重新定义注释在呼叫站点具有不希望的副作用的配置?或者是否有另一种方法来解决这个Java 6/7互操作性问题?

一个相关的问题:

uk4*_*4sx 2

问题:这保证有效吗?

答:这要看情况。我想指出一个潜在的问题。

“真正的”@SafeVarargs 注释是用 RetentionPolicy.RUNTIME 声明的(请参阅此处)。这样做的原因(与具有 RetentionPolicy.SOURCE 的 @Override 相比)可能是为了允许编译器在调用站点检查它。然而,

  • 如果您的 SafeVarargs 注释版本是使用 RetentionPolicy.RUNTIME 声明的
  • 并且使用它的代码是使用 JRE 6 运行的(不包含此注释)
  • 并且您的 SafeVarargs 注释版本位于类路径上

那么任何使用反射在运行时获取方法注释的代码(例如 Spring 框架)都将因 SecurityException 而惨败,因为注释的包名称以“java”开头。(请参阅 ClassLoader.preDefineClass() 方法和下面的 stactrace 中的相关代码,均来自 Sun JRE 1.6.0_31)。

如果注释在编译时位于类路径上,但不在运行时(maven 中的“提供”范围),则不会抛出异常(至少对于 Sun JRE 而言)。

最好的解决方案是拥有一些像 java.lang.java7-annotations 这样的 Maven 工件,并在“provided”范围内使用它。我在这里找到了一些东西(工件:com.google.backport.safevarargs),但它不在中央存储库中。


if ((name != null) && name.startsWith("java.")) {
    throw new SecurityException("禁止的包名称:" +
                                 name.substring(0, name.lastIndexOf('.')));
}
线程“main”中出现异常 java.lang.SecurityException:禁止的包名称:java.lang
    在 java.lang.ClassLoader.preDefineClass(ClassLoader.java:479)
    在 java.lang.ClassLoader.defineClassCond(ClassLoader.java:625)
    在 java.lang.ClassLoader.defineClass(ClassLoader.java:615)
    在 java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
    在 java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
    在 java.net.URLClassLoader.access$000(URLClassLoader.java:58)
    在 java.net.URLClassLoader$1.run(URLClassLoader.java:197)
    在 java.security.AccessController.doPrivileged(本机方法)
    在 java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    在 java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    在 java.lang.ClassLoader.loadClass(ClassLoader.java:247)