@SafeVarargs和Java 6的互操作性

7
我在我的 API 中有一个带有通用可变参数的方法。我希望我的 API 兼容 Java 6 的源代码和二进制代码,但如果 Java 7 的 API 消费者不再遭受不必要的 "varargs" 警告会很好。
我想到的一个技巧是将自己的 java.lang.SafeVarargs 注释添加到我的 API 中,并随着我的可交付成果一起发布。这样做的效果如下:
- Java 6 编译器不会识别此注释,只会忽略它。 - Java 7 编译器将识别此注释,并可能 (?) 首先从 JDK 中加载这个注释,因此它们将不再产生令人讨厌的警告。
除了许可证的问题之外,这是否有保证能够正常工作呢?它似乎可以在 javac 中工作。或者是否存在重新定义来自 JDK 的注释在调用现场具有不良副作用的配置? 或者还有其他解决 Java 6/7 互操作性问题的方法吗?
一个相关的问题:
- 在 Java 6 中使用 Java 7 SDK 特性

@Downvoter:可以解释一下吗? - Lukas Eder
你找到这个问题的解决方案了吗? - Joetjah
我不完全理解这个问题,但如果警告是一个问题,只要确信没有真正的原因受到警告,它们就可以被抑制。 - Trilarion
@Trilarion:不,你没有理解问题的本质 :-) 我不想把抑制警告的负担留给我的API使用者。我想使用声明位置的@SafeVarargs注释,但这在Java 6中不可用。 - Lukas Eder
1个回答

2

问题:这肯定会起作用吗?

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

"真正的" @SafeVarargs 注释是使用 RetentionPolicy.RUNTIME 声明的(请参见此处)。与 @Override 相比,其原因可能是为了允许编译器在调用点检查它。然而:

  • 如果你的 SafeVarargs 版本是以 RetentionPolicy.RUNTIME 声明的
  • 并且使用它的代码在使用不包含此注释的 JRE 6 中运行
  • 并且你的 SafeVarargs 版本在类路径上

那么任何在运行时使用反射获取方法注释的代码(例如 Spring 框架)都将由于注释的包名以 "java." 开头而遭受可怕的 SecurityException 失败(请参见来自 Sun JRE 1.6.0_31 的 ClassLoader.preDefineClass() 方法和 stactrace 中的相关代码)。

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

最好的解决方案是使用某些 Maven 构件,例如 java.lang.java7-annotations,并使用 "提供" 范围。我在这里发现了一些东西(构件:com.google.backport.safevarargs),但它不在中央存储库中。


if ((name != null) && name.startsWith("java.")) {
    throw new SecurityException("Prohibited package name: " +
                                 name.substring(0, name.lastIndexOf('.')));
}
Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
    at java.lang.ClassLoader.preDefineClass(ClassLoader.java:479)
    at java.lang.ClassLoader.defineClassCond(ClassLoader.java:625)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
    at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接