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

Ice*_*ras 15 java maven-2 maven-release-plugin

我有这个项目由多个罐子和战争组成的耳朵.我在快照中构建了所有内容,效果很好.然后我为每个项目发布了一个版本,发现罐子和战争的大小与快照略有不同.

比较文件到文件我意识到.class文件都在那里,但略大或稍大,一般不超过40个字节.

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

感谢您的输入.

Luc*_*cas 19

--- SPOILER ALERT ---

简短的回答是,为了将源代码编译为旧版本,您需要同时提供-source选项以及-bootclasspath.看到这篇文章.如果你想编译源到新的版本,你需要设置<source>,<target>,<compilerVersion>,<fork>,和<executable>编译器插件,设置<jvm>在万无一失的插件...

而现在的故事......

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

  <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>
Run Code Online (Sandbox Code Playgroud)

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

[INFO] [DEBUG] Command line options:
[INFO] [DEBUG] -d C:\... -nowarn -target 1.6 -source 1.6 -encoding UTF-8
Run Code Online (Sandbox Code Playgroud)

请注意,为简洁起见,...代替实际参数

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

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
Run Code Online (Sandbox Code Playgroud)

这将打印出与-source 1.6无法一起设置的方便花花公子警告引导类路径.有点谷歌搜索引发了这篇文章,其中指出:

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

  • 使用较旧的-source设置.
  • 将bootclasspath设置为针对旧平台的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>
Run Code Online (Sandbox Code Playgroud)

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

  <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>
Run Code Online (Sandbox Code Playgroud)

而现在你只需要使${java.home}变量提供给您MVN(通过-D系统属性,或通过普通的旧的环境变量,或者你可以得到真正看中的东西和它在Java 6的个人资料的用户设置).

现在只需运行你的构建,然后去拿一杯冰镇啤酒吧......

----编辑----

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

----编辑2 ----

为了笑容,我尝试了另一个方向.我没有使用Java 7编译为java 6运行maven,而是使用java 6编译java for maven.第一次尝试非常简单:

  <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>
Run Code Online (Sandbox Code Playgroud)

基本上,我设置我的<source><target>1.7,但这显然是不够的,因为6不能编译7代码.回到编译器插件,实际上有一个示例页面描述了需要做什么.也就是说,您需要<fork>使用java 7关闭新进程<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] ------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

什么是UnsupportedClassVersionError?仔细看看告诉我们它的maven-surefire-plugin失败了.所以我尽力mvn compile而且确定我获得了成功,因为surefire插件从未激发过.所以我跑去mvn -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"
Run Code Online (Sandbox Code Playgroud)

好吧,所以它运行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.
Run Code Online (Sandbox Code Playgroud)

由于我们使用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>
Run Code Online (Sandbox Code Playgroud)

并启动构建......

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)


Ben*_*nus 1

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

javap -verbose MyClass
Run Code Online (Sandbox Code Playgroud)

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

然后使用这个表:

主要次要 Java 平台版本
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 大小差异可能是由于编译版本造成的,也可能是由于其他编译选项造成的,例如使用调试信息进行编译(堆栈跟踪中的行号)。