在使用较新的JDK构建的库的API级别上验证向后兼容性

问题描述 投票:0回答:2

最近,一个队友在我们的Java 8代码中使用了以下功能:Matcher.replaceAll​(Function replacer)。该函数是在Java 9中引入的,但是由于他使用的是较新的编译器,因此仅在JDK的rt.jar中找到了API函数,没有人注意到这在真正的Java 8环境中不起作用。兼容性设置正确设置,并且gradle子项目具有以下设置:

sourceCompatibility = 1.8
targetCompatibility = 1.8

当我第一次在Java 5代码中使用Java 6函数String.isEmpty时,我遇到了非常相似的问题。

我可以采取什么措施来强制使用正确的API。因为它是一个共享库,所以我是否必须为此gradle子项目使用(以及安装,维护..)其他JDK,或者是否存在某种兼容的扫描程序,该扫描程序通过内置的jar运行并检查所有rt引用?

java gradle compatibility
2个回答
1
投票

您已经注意到,这两个兼容性配置不考虑较旧版本的API-仅考虑语法,语义和生成的字节码。

您可以采取两种选择。一种是在计算机上安装JDK 8,然后配置Gradle以在编译项目时使用它。看起来像这样:

tasks.withType(JavaCompile) {
    options.fork = true
    options.forkOptions.executable = "$java8Home/bin/javac"
    options.bootstrapClasspath = files("$java8Home/jre/lib/rt.jar")
}

这里的缺点是,您首先需要安装JDK 8,并且由于它可能安装在不同的位置,所以您可能需要使用环境变量或属性对其进行配置(我已经将其命名为java8Home

但是,从Java 9开始,JDK现在知道以前版本的文档API,您可以通过新的--release标志选择使用哪个API。如果使用未公开的API,这将行不通,但这意味着您可以使用任何版本的Java编译项目,并且仍然使生成的类与Java 8兼容。您可以这样操作:

tasks.withType(JavaCompile) {
    if (JavaVersion.current() > JavaVersion.VERSION_1_8) {
        options.compilerArgs.addAll(['--release', '8'])
    }
}

注意,只有在您仍然需要通过Java 8(通过JAVA_HOME变量)支持运行Gradle的情况下,才使用'if'语句。如果仅使用更高版本,则可以将其删除,因此您始终要设置“ compilerArgs”。


1
投票

对于某些版本的Java,可以在较新的JDK上构建Java代码以在较旧的JDK / JRE上运行。您已经发现--source--targetjavac选项以及相应的Gradle设置。您可以做的另一件事是使用--bootclasspath告诉javac针对较旧版本的Java的运行时库进行编译。

由于您正在使用Gradle,请检查“ gradle-java-cross-compile-plugin”(https://github.com/nebula-plugins/gradle-java-cross-compile-plugin)。我找不到有关它的任何文档,但显然它处理的是--target--bootclasspath


话虽如此,我认为交叉编译Java不是一个好的解决方案。

我实际上建议您为您想要支持的所有Java版本安装带有JDK安装的持续集成(CI)服务器(例如Jenkins)。然后设置作业以构建代码对每个Java版本运行单元测试。

© www.soinside.com 2019 - 2024. All rights reserved.