15

我有这个项目由多个罐子和战争制作而成。我在快照中构建所有内容,并且效果很好。然后我为每个项目发布了一个版本,发现 jars 和 war 的大小与快照的大小略有不同。

比较文件,我意识到 .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>

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

<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 中编译发布插件吗?

感谢您的输入。

4

4 回答 4

19

--- 剧透警告 ---

简短的回答是,为了将源代码编译为旧版本,您需要同时提供-source选项和-bootclasspath. 见这篇文章。如果你想把源码编译成更新的版本,你需要在编译器插件上设置, <source>, <target>, <compilerVersion>, <fork>, 并在surefire插件设置...<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>

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

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

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

在输出中。开头的消息-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

这会打印出未与 -source 1.6 一起设置的方便的警告引导类路径。在谷歌上搜索一下就会出现这篇文章,其中指出:

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

  • 使用较旧的 -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>

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

现在只需运行你的构建并在它突然消失的时候去喝一杯冰镇啤酒......

- - 编辑 - -

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

---- 编辑 2 ----

为了笑容,我尝试了另一个方向。我没有使用为 java 6 编译的 java 7 运行 maven,而是使用为 java 7 编译的 java 6 运行 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>

基本上,我将我的<source>and设置<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] ------------------------------------------------------------------------

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"

好的,所以它正在运行 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] ------------------------------------------------------------------------
于 2012-07-12T23:23:17.020 回答
1

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

javap -verbose MyClass

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

于 2010-09-03T20:14:38.100 回答
0

可能是发布插件在 1.6 或其他版本中编译,解释类大小差异?

不能是IMO。Maven 发布插件不编译任何东西,它只是触发一个阶段,该阶段本身将触发compile阶段和 Maven 编译器插件。换句话说,将使用 Maven 编译器插件及其设置。

您可以使用以下命令来准确控制正在发生的事情:

mvn help:active-profiles -Prelease

检查配置文件。和

mvn help:effective-pom -Prelease

检查有效的pom。

于 2010-09-03T22:53:12.833 回答
0

请注意,如果选择了错误的版本,您将收到类似的错误

xxxx is not supported in -source 1.5
[ERROR] (use -source 7 or higher to enable yyyy)

在 maven 发布期间,maven 发布插件(设置/默认为)编译器版本 1.5。为确保它选择正确的版本,请指定属性。

<properties>
 <maven.compiler.source>1.7</maven.compiler.source>
 <maven.compiler.target>1.7</maven.compiler.target>
</properties>
于 2017-08-24T17:42:09.303 回答