Maven 发布插件:指定 java 编译器版本

2022-09-03 13:58:49

我有一个由多个罐子和战争组成的项目来制作耳朵。我在快照中构建所有内容,它工作得很好。然后,我为每个项目制作了一个版本,发现罐子和战争的大小与快照项目略有不同。

比较文件到文件,我意识到.class文件都在那里,但略大或更大,通常不超过40字节。

我强制编译以使用java 1.5在Maven中使用此标签:

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target> 
                </configuration>

我将此标记用于发布插件:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-release-plugin</artifactId>
    <version>2.0</version>
    <configuration>
        <releaseProfiles>release</releaseProfiles>
        <goals>deploy</goals>
    </configuration>
</plugin>

可能是发布插件正在以1.6或其他版本编译,解释类大小差异?如果是这样,我可以让发布插件在1.5中编译吗?

感谢您的输入。


答案 1

---剧透预警---

简短的答案是,为了将源代码编译为旧版本,您需要同时提供选项和.请参阅此文章。而如果你想将源代码编译到更新的版本,你需要在编译器插件上设置、、、、和,并在surefire插件上设置...-source-bootclasspath<source><target><compilerVersion><fork><executable><jvm>

现在的故事...

我遇到了同样的问题。事实证明,编译以前的版本可能不如设置和那么容易。我的具体情况是,我有一个Java 1.7 JDK,我的类与1.7不兼容(他们向我正在实现的接口添加了一个新方法)。当我尝试编译它时,编译器给了我一条错误消息,指出我没有实现接口方法。无论如何,我尝试设置编译器插件:<source><target>

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
      <encoding>UTF-8</encoding>
    </configuration>
  </plugin>

但是当我运行构建时,我得到了同样的错误。所以我在调试中运行了maven,并看到了这个:

[INFO] [DEBUG] Command line options:
[INFO] [DEBUG] -d C:\... -nowarn -target 1.6 -source 1.6 -encoding UTF-8

请注意, ...为了简洁起见,代替了实际的论点

在输出中。以 开头的消息是实际的完整编译参数列表。因此,如果删除该标志并将其余部分粘贴到命令行上,则可以看到编译器的实际输出:-d-nowarnjavac

javac -d C:\... -target 1.6 -source 1.6 -encoding UTF-8
warning: [options] bootstrap class path not set in conjunction with -source 1.6

这将打印出未与 -source 1.6 一起设置的 handy-dandy 警告引导类路径。稍微谷歌搜索一下,就会发现这篇文章,其中指出:

要使用 Javac 从 JDK N 交叉编译器到较旧的平台版本,正确的做法是:

  • 使用较旧的 -source 设置。
  • 将引导类路径设置为针对旧平台的 rt.jar(或等效项)进行编译。

如果不采取第二步,javac将尽职尽责地使用旧语言规则与新库相结合,这可能导致类文件在旧平台上不起作用,因为可以包含对不存在的方法的引用。

现在引用编译器插件的 maven 文档,给出:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.5.1</version>
    <configuration>
      <compilerArguments>
        <verbose />
        <bootclasspath>${java.home}\lib\rt.jar</bootclasspath>
      </compilerArguments>
    </configuration>
  </plugin>

然后,您可以将其与早期配置相结合,以获得:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
      <encoding>UTF-8</encoding>
      <bootclasspath>${java.home}\lib\rt.jar</bootclasspath>
    </configuration>
  </plugin>

现在,您只需要使该变量可用于您的 mvn(通过 -D 系统属性,或通过普通的旧环境变量,或者您可以变得非常花哨,并将其填充到用户设置的 java 6 配置文件中)。${java.home}

现在只需运行您的构建,然后去拿一杯冰镇啤酒,而它却在摇晃......

---- 编辑----

最后一件事...在 bootclasspath 中包含 rt.jar 始终是必需的,但是,我发现根据具体情况可能需要更多。我必须包含jce.jar(与rt.jar位于同一目录中),因为我的应用程序正在执行加密工作。

---- 编辑 2 ----

为了咧嘴一笑,我从另一个方向尝试了一下。我没有运行 java 7 编译 java 6 的 maven,而是运行了 java 6 编译的 java 7。第一次尝试非常简单:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.5.1</version>
    <configuration>
      <source>1.7</source>
      <target>1.7</target>
      <fork>true</fork>
      <verbose>true</verbose>
      <compilerVersion>1.7</compilerVersion>
      <executable>${JAVA_7_HOME}/bin/javac</executable>
      <encoding>UTF-8</encoding>
    </configuration>
  </plugin>

基本上,我将 my 和 设置为 1.7,但这显然是不够的,因为 6 无法编译 7 代码。所以回到编译器插件,实际上有一个示例页面描述了需要做什么。也就是说,您需要使用java 7关闭新进程。所以现在我想我已经准备好了。是时候启动构建了...<source><target><fork><executable>

C:\Projects\my-project>mvn package
...
Caused by: java.lang.UnsupportedClassVersionError: mypackage.StupidTest : Unsup
ported major.minor version 51.0
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

到底是什么 不受支持的类版本错误?仔细观察就会告诉我们,是 maven-surefire-plugin 失败了。所以我尝试了,果然我得到了成功,因为surefire插件从未启动过。所以我跑了一圈,注意到了这个宝石:mvn compilemvn -X package

Forking command line: cmd.exe /X /C ""C:\Program Files\Java\jdk1.6.0_29\jre\bin\
java" -jar C:\Projects\my-project\target\surefire\surefirebooter2373372991878002
398.jar C:\Projects\my-project\target\surefire\surefire1861974777102399530tmp C:
\Projects\my-project\target\surefire\surefire4120025668267754796tmp"

好的,所以它运行的java 6。为什么?surefire的文档给出了这个:

jvm:
Option to specify the jvm (or path to the java executable) to use with the forking 
options. For the default, the jvm will be a new instance of the same VM as the one 
used to run Maven. JVM settings are not inherited from MAVEN_OPTS.

由于我们使用java 6 VM运行mvn,因此它分叉了一个java 6 VM用于其单元测试。因此,请适当地设置此选项:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.12</version>
    <configuration>
      <jvm>${JAVA_7_HOME}/bin/java</jvm>
    </configuration>
  </plugin>

并启动构建...

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

答案 2

您可以使用 JDK 附带的 javap 实用程序来验证编译类的版本。从命令行:

javap -verbose MyClass

在javap的输出中寻找“次要版本”和“主要版本”大约十行。

然后使用此表:

major       minor       Java platform version
45          3           1.0
45          3           1.1
46          0           1.2
47          0           1.3
48          0           1.4
49          0           1.5
50          0           1.6

.class大小差异可能是由于编译版本,也可能是由于其他编译选项,例如使用调试信息(堆栈跟踪中的行号)进行编译。


推荐