【问题标题】:Specifying Java version in maven - differences between properties and compiler plugin在 Maven 中指定 Java 版本 - 属性和编译器插件之间的差异
【发布时间】:2016-12-17 08:23:36
【问题描述】:

我对 Maven 不是很有经验,在尝试多模块项目时,我开始想知道如何为父 Maven pom 中的所有子模块指定 Java 版本。直到今天我只使用:

<properties>
    <java.version>1.8</java.version>
</properties>

...但是在研究时我发现您也可以在 Maven 编译器插件中指定 Java 版本,如下所示:

<plugins>
    <plugin>    
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

然后将其包装到插件管理标签中以启用子 poms 的使用。所以第一个问题是这样的:

在属性和 Maven 编译器插件中设置 Java 版本有什么区别?

我找不到明确的答案,但在研究过程中我发现您也可以通过这种方式指定 Java 版本:

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

...这表明编译器插件存在,即使我没有明确声明它。运行mvn package 输出与

maven-compiler-plugin:3.1:compile (default-compile) @ testproj ---

...还有一些我没有声明的插件。

那么这些插件是 Maven pom 的默认隐藏部分吗?在属性和 Maven 插件配置元素中设置源/目标有什么区别吗?

其他一些问题是 - 应该使用哪种方式(如果它们不相等,何时使用)?哪一个最适合多模块项目,如果 pom 中指定的 Java 版本与 JAVA_HOME 中指定的版本不同会怎样?

【问题讨论】:

标签: java maven maven-3 maven-compiler-plugin


【解决方案1】:

如何指定JDK版本?

使用以下三种方式中的任何一种:(1) Spring Boot 功能,或将 Maven 编译器插件与 (2) source & target 或 (3) 与 release 一起使用。

春季启动

  1. &lt;java.version&gt; 未在 Maven 文档中引用。
    这是 Spring Boot 的特殊性。
    它允许将源和目标 java 版本设置为相同的版本,例如为两者指定 java 1.8:

    1.8

如果您使用 Spring Boot,请随意使用它。

maven-compiler-pluginsource & target

  1. 使用maven-compiler-pluginmaven.compiler.source/maven.compiler.target 属性是等效的。

确实如此:

<plugins>
    <plugin>    
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
</plugins>

相当于:

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

根据Maven documentation of the compiler plugin 因为编译器配置中的&lt;source&gt;&lt;target&gt; 元素使用属性maven.compiler.sourcemaven.compiler.target(如果已定义)。

source

Java 编译器的 -source 参数。
默认值为:1.6
用户属性为:maven.compiler.source

target

Java 编译器的 -target 参数。
默认值为:1.6.
用户属性为:maven.compiler.target

关于sourcetarget 的默认值,请注意 since the 3.8.0 of the maven compiler, the default values have changed from 1.5 to 1.6.

maven-compiler-pluginrelease 而不是 source & target

  1. maven-compiler-plugin3.6及以后的版本提供了一种新的方式:

    org.apache.maven.plugins maven 编译器插件 3.8.0 9

你也可以只声明:

<properties>
    <maven.compiler.release>9</maven.compiler.release>
</properties>

但此时它不会起作用,因为您使用的maven-compiler-plugin 默认版本不依赖于足够新的版本。

Maven release 参数传达 release :我们可以从 Java 9 传递的 new JVM standard option

针对公共、受支持和记录的 API 编译 特定的 VM 版本。

这种方式提供了一种为sourcetargetbootstrap JVM 选项指定相同版本的标准方式。
请注意,指定bootstrap 是交叉编译的好习惯,如果您不进行交叉编译也不会受到影响。


指定 JDK 版本的最佳方式是什么?

第一种方式(&lt;java.version&gt;)只有在使用 Spring Boot 时才允许使用。

对于 Java 8 及以下版本:

关于其他两种方法:使用maven-compiler-plugin 评估maven.compiler.source/maven.compiler.target 属性,您可以使用其中一种。它没有改变任何事实,因为最终这两种解决方案依赖于相同的属性和相同的机制:maven 核心编译器插件。

好吧,如果您不需要在编译器插件中指定除 Java 版本之外的其他属性或行为,那么使用这种方式更有意义,因为这样更简洁:

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

来自 Java 9:

release 参数(第三点)是一种强烈考虑是否要对源和目标使用相同版本的方法。

如果 JAVA_HOME 中的 JDK 版本与 pom.xml 中指定的版本不同会怎样?

JAVA_HOME 引用的 JDK 是否与 pom 中指定的版本兼容不是问题,但为了确保更好的交叉编译兼容性,请考虑添加 bootstrap JVM 选项,并将路径作为值target 版本的rt.jar

需要考虑的重要一点是,Maven 配置中的sourcetarget 版本不应优于JAVA_HOME 引用的JDK 版本。
较旧版本的 JDK 无法与较新版本一起编译,因为它不知道其规范。

根据使用的JDK获取源、目标和发布支持的版本信息,请参考java compilation : source, target and release supported versions


JAVA_HOME引用的JDK与pom中指定的java目标和/或源版本不兼容如何处理?

例如,如果您的JAVA_HOME 引用 JDK 1.7,并且您在 pom.xml 的编译器配置中指定 JDK 1.8 作为源和目标,这将是一个问题,因为如前所述,JDK 1.7 没有不知道如何编译。
从它的角度来看,它是一个未知的JDK版本,因为它是在它之后发布的。
在这种情况下,您应该配置 Maven 编译器插件以通过这种方式指定 JDK:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <compilerVersion>1.8</compilerVersion>      
        <fork>true</fork>
        <executable>D:\jdk1.8\bin\javac</executable>                
    </configuration>
</plugin>

您可以在examples with maven compiler plugin了解更多详情。


没有询问,但可能更复杂的情况是您指定源而不是目标。它可能会根据源版本在目标中使用不同的版本。规则是特殊的:你可以在the Cross-Compilation Options part阅读它们。


为什么在执行 Maven package 目标时在输出中跟踪编译器插件,即使您没有在 pom.xml 中指定它?

要编译您的代码,并且更普遍地执行 Maven 目标所需的所有任务,Maven 需要工具。因此,它使用核心 Maven 插件(您可以通过其groupId 识别核心 Maven 插件:org.apache.maven.plugins)来执行所需的任务:用于编译类的编译器插件,用于执行测试的测试插件等等......所以,即使你不声明这些插件,它们也会绑定到 Maven 生命周期的执行。
在 Maven 项目的根目录中,您可以运行命令:mvn help:effective-pom 以有效使用最终的 pom。除了其他信息之外,您还可以看到 Maven 附加的插件(在您的 pom.xml 中指定或未指定)、使用的版本、它们的配置以及生命周期每个阶段的执行目标。

mvn help:effective-pom 命令的输出中,您可以在&lt;build&gt;&lt;plugins&gt; 元素中看到这些核心插件的声明,例如:

...
<plugin>
   <artifactId>maven-clean-plugin</artifactId>
   <version>2.5</version>
   <executions>
     <execution>
       <id>default-clean</id>
       <phase>clean</phase>
       <goals>
         <goal>clean</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
 <plugin>
   <artifactId>maven-resources-plugin</artifactId>
   <version>2.6</version>
   <executions>
     <execution>
       <id>default-testResources</id>
       <phase>process-test-resources</phase>
       <goals>
         <goal>testResources</goal>
       </goals>
     </execution>
     <execution>
       <id>default-resources</id>
       <phase>process-resources</phase>
       <goals>
         <goal>resources</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
 <plugin>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>3.1</version>
   <executions>
     <execution>
       <id>default-compile</id>
       <phase>compile</phase>
       <goals>
         <goal>compile</goal>
       </goals>
     </execution>
     <execution>
       <id>default-testCompile</id>
       <phase>test-compile</phase>
       <goals>
         <goal>testCompile</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
  ...

您可以在the introduction of the Maven lifeycle in the Maven documentation了解更多信息。

尽管如此,当您想将这些插件配置为其他值作为默认值时,您可以声明这些插件(例如,您在 pom.xml 中声明 maven-compiler 插件以调整要使用的 JDK 版本时就这样做了)或者当你想添加一些在 Maven 生命周期中默认不使用的插件执行时。

【讨论】:

  • 感谢您的广泛解释,现在我更清楚了。还有关于 - 我在一些代码 sn-p 中看到了这一点,也许那是一些自定义属性,我错误地认为这是声明 java 版本的方式,从现在开始将坚持&lt;maven.compiler.x&gt; 属性开。
  • "如果您的 JAVA_HOME 的 JDK 与 pom 中指定的版本兼容,这不是问题" 这不是(不一定)正确,请检查 this Stack溢出线程供参考
  • @Robin A. Meade 感谢您的反馈。我使用弹簧靴,但我不知道。就我个人而言,我认为它不够标准,无法用作或引用为可以使用的东西。 Spring Boot 提供了一些非常有趣的东西,但在某些情况下,它的特性非常可争议。覆盖标准 maven 属性的名称以不填充源 jdk 和目标 jdk 看起来确实是一个坏主意,因为它为应用程序执行一次。您失去了在应用程序中保留简单 xml 行的标准。哇 !好主意……
  • @MasterJoe2 你可以在 10 版本的官方 javac 文档中找到它:docs.oracle.com/javase/10/tools/javac.htm#JSWOR627。我把这个答案分成两部分,因为它太大了,你也可以看看:stackoverflow.com/questions/51692748/…
  • 棒极了,而且很有描述性。谢谢!
【解决方案2】:

以上解决方案都没有立即对我有用。所以我按照以下步骤操作:

  1. 添加pom.xml:
<properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
</properties>
  1. 转到Project Properties > Java Build Path,然后删除 JRE 系统库指向JRE1.5

  2. 强制更新项目。

【讨论】:

  • 您为 Java 10 及更高版本指定了哪个版本?是 10 还是 1.10 ?
  • @MasterJoe2 from java 9及以上版本你需要按原样写版本号( 10 ),对于以下版本,你必须添加1。版本前面(1.5
【解决方案3】:

以下步骤对我来说就像魅力一样!所以想和大家分享。

这些是我在 pom.xml 文件中添加的用于处理基本项目的行。我正在使用 Java 12(您可以替换您的 11、10、1.8 等)。

<properties>
    <maven.compiler.source>12</maven.compiler.source>
    <maven.compiler.target>12</maven.compiler.target>
</properties>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <release>12</release>
            </configuration>
        </plugin>
    </plugins>
</build>

更改 pom 文件后,请重新加载您的项目,以便 IDE 可以将插件下载/获取到项目中。 (对于 IntelijIDEA:右键单击 pom.xml -> 转到 maven -> 重新加载项目)。

请确保在您的 IDE 中也配置所需的版本。

【讨论】:

    【解决方案4】:

    如果您使用的是 IntelliJ idea maven build。

    【讨论】:

      【解决方案5】:

      考虑替代方案:

      <properties>
          <javac.src.version>1.8</javac.src.version>
          <javac.target.version>1.8</javac.target.version>
      </properties>
      

      它应该与maven.compiler.source/maven.compiler.target 相同,但上面的解决方案对我有用,否则第二个得到父规范(我有一个 .pom 的 matrioska)

      【讨论】:

        【解决方案6】:

        对于 NetBeans IDE,更改项目属性 - (Jersey Service) - 类别 > 源 > 选择“源/二进制格式”为 1.8。

        【讨论】:

        • 这不是问题的答案:“指定 Java 版本 in maven”。你的回答,无论多么有效,都是在回答别的问题。
        猜你喜欢
        • 2011-04-07
        • 2019-04-30
        • 1970-01-01
        • 1970-01-01
        • 2019-02-25
        • 1970-01-01
        • 2013-05-19
        相关资源
        最近更新 更多