Ame*_*sse 3 java jdk1.5 cross-compiling maven
POM包含(如/sf/answers/1567929891/中所述):
<profile>
<id>compileWithJava5</id>
<!--
NOTE
Make sure to set the environment variable JAVA5_HOME
to your JDK 1.5 HOME when using this profile.
-->
<properties>
<java.5.home>${env.JAVA5_HOME}</java.5.home>
<java.5.libs>${java.5.home}/jre/lib</java.5.libs>
<java.5.bootclasspath>${java.5.libs}/rt.jar${path.separator}${java.5.libs}/jce.jar</java.5.bootclasspath>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<compilerArguments>
<bootclasspath>${java.5.bootclasspath}</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</profile>
Run Code Online (Sandbox Code Playgroud)
$JAVA5_HOME
设置:
• echo $JAVA5_HOME
/usr/lib/jvm/jdk1.5.0_22
Run Code Online (Sandbox Code Playgroud)
据我所知,Java + Maven的神奇之处在于,它应该是maven-compiler-plugin
指示JDK 1.8伪装成JDK 1.5并使用Java 5引导类路径的有效咒语.
根据为什么javac在@Override注释上失败,JDK 1.5将不允许接口的已@Override
实现方法,仅允许在超类中存在的重写方法.
在此提交中,@Override
注释用于接口的已实现方法,因此这是无效的Java 5代码:
private static class DummyEvent implements PdfPTableEvent {
@Override
public void tableLayout(PdfPTable table, float[][] widths, float[] heights, int headerRows, int rowStart, PdfContentByte[] canvases) {
}
}
Run Code Online (Sandbox Code Playgroud)
我跑的时候
mvn clean compile test-compile -P compileWithJava5
Run Code Online (Sandbox Code Playgroud)
我没有在包含@Override
注释的类上得到编译错误.我在这里错过了什么?
(已经尝试过:Animal Sniffer Maven插件,但该插件不会查看编译标志,只能查看字节代码.)
编辑:这是我目前在我的POM中所拥有的.
<profile>
<id>compileWithLegacyJDK</id>
<!--
NOTE
Make sure to set the environment variable JAVA5_HOME
to your JDK 1.5 HOME when using this profile.
-->
<properties>
<java.version>1.5</java.version>
<java.home>${env.JAVA5_HOME}</java.home>
<java.libs>${java.home}/jre/lib</java.libs>
<java.bootclasspath>${java.libs}/rt.jar${path.separator}${java.libs}/jce.jar</java.bootclasspath>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArguments>
<bootclasspath>${java.bootclasspath}</bootclasspath>
</compilerArguments>
<compilerVersion>${java.version}</compilerVersion>
<fork>true</fork>
<executable>${java.home}/bin/javac</executable>
</configuration>
</plugin>
</plugins>
</build>
</profile>
Run Code Online (Sandbox Code Playgroud)
运行
export JAVA5_HOME=/var/lib/jenkins/tools/hudson.model.JDK/1.5
mvn compile test-compile -P compileWithLegacyJDK
Run Code Online (Sandbox Code Playgroud)
有关更多详细信息,请参阅下面的接
问题的核心:Maven仍在使用启动它的JDK编译代码.由于您正在使用JDK 8,它正在使用JDK 8进行编译,并且要使用其他编译器进行编译,因此您需要使用工具链或指定正确JDK的路径.
要测试此答案,您可以使用以下POM创建一个简单的Maven项目
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
<compilerArguments>
<bootclasspath>/usr/lib/jvm/jdk1.5.0_22/jre/lib/rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
Run Code Online (Sandbox Code Playgroud)
用一个类编译坐下src/main/java/test
,是:
package test;
interface I {
void foo();
}
public class Main implements I {
public static void main(String[] args) {
new Main().foo();
}
@Override
public void foo() {
System.out.println("foo");
}
}
Run Code Online (Sandbox Code Playgroud)
这看起来像是一个配置为使用JDK 5的标准Maven项目.请注意,该类使用@Override
实现接口的方法.在Java 6之前不允许这样做.
如果您尝试使用在JDK 8下运行的Maven构建此项目,它将进行编译,尽管设置<source>1.5</source>
.
Maven编译器插件没有错.javac
是责备.设置该-source
标志不会告诉javac
您使用此特定JDK版本编译项目.它指示javac
仅接受特定版本的源代码.来自javac
文档:
-source release
:指定接受的源代码版本.
例如,如果您指定了-source 1.4
,那么您尝试编译的源代码不能包含泛型,因为稍后会将这些代码引入该语言.该选项强制应用程序的源兼容性.使用Java 5泛型的Java应用程序与使用JDK 4编译器的Java 4程序源不兼容.同样,使用Java 8 lambda表达式的应用程序与JDK 6编译器不兼容.
在这种情况下,@Override
是Java 5中已经存在的注释.但是,它的语义在Java 6中发生了变化.因此@Override
,无论是否在实现接口的方法上使用的代码都与Java 5程序源兼容.因此,-source 1.5
在这样的类上运行JDK 8 不会失败.
在第二个参数上:target
.同样,这不是Maven编译器的关注点,而是javac
一个问题.虽然该-source
标志强制与旧版本的源兼容性,但-target
强制与旧版本的二进制兼容性.该标志告诉javac
您生成与旧JVM版本兼容的字节代码.它没有告诉javac
检查编译的代码是否可以实际运行旧的JVM版本.为此,您需要设置一个bootclasspath
,它将使用指定的JDK交叉编译您的代码.
显然,@Override
实现接口的方法不能在Java 5 VM上运行,所以javac
应该在这里吠叫.但都能跟得上:Override
具有源保留,这意味着编译发生后的注释是完全丢弃.这也意味着当交叉编译发生时,注释不再存在; 在使用JDK 8进行编译时,它被丢弃.正如您所知,这也是为什么像Animal Sniffer Plugin这样的工具(它能够自动bootclasspath
使用预定义的JDK版本)不能检测到这一点:缺少注释.
总之,您可以将上面的示例应用程序打包并mvn clean package
运行在JDK 8上,然后运行它而不会在Java 5 JVM上遇到任何问题.它会打印出来"foo"
.
有两种可能的解决方案.
第一个是javac
直接的,指定通过executable
Compiler Plugin属性的路径:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
<compilerArguments>
<bootclasspath>/usr/lib/jvm/jdk1.5.0_22/jre/lib/rt.jar</bootclasspath>
</compilerArguments>
<compilerVersion>1.5</compilerVersion>
<fork>true</fork>
<!-- better to have that in a property in the settings, or an environment variable -->
<executable>/usr/lib/jvm/jdk1.5.0_22/bin/javac</executable>
</configuration>
</plugin>
Run Code Online (Sandbox Code Playgroud)
这将设置编译器应该与compilerVersion
参数一起使用的JDK的实际版本.这是一种简单的方法,但请注意,它只会更改用于编译的JDK版本.Maven仍将使用启动它的JDK 8安装来生成Javadoc或运行单元测试,或任何需要JDK安装工具的步骤.
第二种全球方法是使用工具链.这些将指示Maven使用与用于启动的JDK不同的JDK mvn
,并且每个Maven插件(或任何知道工具链的插件)将使用此JDK来执行其操作.编辑您的POM文件以添加以下插件配置maven-toolchains-plugin
:
<plugin>
<artifactId>maven-toolchains-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>1.5</version>
</jdk>
</toolchains>
</configuration>
</plugin>
Run Code Online (Sandbox Code Playgroud)
缺少的成分是告诉那些插件,该工具链的配置在哪里.这是在toolchains.xml
文件内部完成的,通常在文件内部~/.m2/toolchains.xml
.从Maven 3.3.1开始,您可以使用--global-toolchains
参数定义此文件的位置,但最好将其保留在用户主目录中.内容如下:
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.5</version>
</provides>
<configuration>
<jdkHome>/usr/lib/jvm/jdk1.5.0_22</jdkHome>
</configuration>
</toolchain>
</toolchains>
Run Code Online (Sandbox Code Playgroud)
这声明了一个类型的工具链,它jdk
为JDK 5提供了JDK home的路径.Maven插件现在将使用此JDK.实际上,它也将是编译源代码时使用的JDK.
如果您尝试使用此添加的配置再次编译上面的示例项目...您将最终出现错误:
方法不会覆盖其超类中的方法