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

发布于 2024-09-17 10:35:46 字数 1163 浏览 13 评论 0原文

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

通过比较文件,我意识到 .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 中编译发布插件吗?

感谢您的意见。

I have this project made of multiple jars and war to make an ear. I build everything in snapshot and it works great. Then I made a release for every single project and saw that the jars and the war were slightly different in size than the snapshot ones.

Comparing file to file I realized that the .class files were all there, but slightly larger or bigger, nothing more than 40 bytes generally.

I force compilation to use java 1.5 using this tag in 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>

I use this tag for the release plugin:

<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>

Could it be that the release plugin is compiling in 1.6 or other, explaining the classes size difference ? If so can I make the release plugin compile in 1.5 ?

Thanks for your input.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

趁微风不噪 2024-09-24 10:35:51

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

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

在 maven release, maven release plugin (sets/defaults to) the compiler version 1.5 之类的错误。为了确保它选择正确的版本,请指定属性。

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

Just a note, if a wrong version is picked up, you will get an error something like

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

During maven release, maven release plugin (sets/defaults to) the compiler version 1.5. To ensure it picks up the correct version specify the properties.

<properties>
 <maven.compiler.source>1.7</maven.compiler.source>
 <maven.compiler.target>1.7</maven.compiler.target>
</properties>
一口甜 2024-09-24 10:35:50

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

国际海事组织不可能。 Maven 发布插件不会编译任何内容,它只是触发一个阶段,该阶段本身会触发 compile 阶段和 Maven 编译器插件。换句话说,将使用 Maven 编译器插件及其设置。

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

mvn help:active-profiles -Prelease

检查配置文件。并

mvn help:effective-pom -Prelease

检查有效的pom。

Could it be that the release plugin is compiling in 1.6 or other, explaining the classes size difference ?

Can't be IMO. The Maven Release Plugin doesn't compile anything, it just triggers a phase that will itself trigger the compile phase and the Maven Compiler Plugin. In other words, the Maven Compiler Plugin and its settings will be used.

You can use the following commands to control what is happening exactly:

mvn help:active-profiles -Prelease

to check profiles. And

mvn help:effective-pom -Prelease

to check the effective pom.

心碎无痕… 2024-09-24 10:35:49

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

You can verify the version a class is compiled for by using the javap utility included with the JDK. From the command line:

javap -verbose MyClass

In the output of javap look for "minor version" and "major version" about ten lines down.

Then use this table:

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

The .class size difference may be due to compile version but also may be due to other compile options like compiling with debug information (line numbers in stacktraces).

孤凫 2024-09-24 10:35:48

--- 剧透警告 ---

简短的回答是,为了将源代码编译为旧版本,您需要提供 -source 选项以及-bootclasspath。请参阅本文。如果要将源代码编译为较新的版本,则需要设置 编译器插件上的 >、设置 关于 Surefire 插件...

现在讲故事...

我遇到了同样的问题。事实证明,编译以前的版本可能不像设置那么容易。我的具体情况是,我有一个 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 开头的消息是实际的完整编译参数列表。 命令行上的 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

因此,如果删除 -nowarn 标志并将其余部分粘贴到 警告引导类路径未与 -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>

然后您可以将其与之前的配置结合起来以获得:

  <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 配置文件中)。

现在只需运行您的构建,然后在它嘎嘎作响的时候去喝杯冰啤酒...

---- 编辑 ----

最后一件事... 在您的 bootclasspath 中包含 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>

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

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 出现了故障。所以我尝试了 mvncompile ,果然我成功了,因为 Surefire 插件从未启动。所以我运行 mvn -X package 并注意到这个 gem:

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] ------------------------------------------------------------------------

--- SPOILER ALERT ---

The short answer is that in order to compile source to an older version, you need to supply both the -source option as well as the -bootclasspath. See this article. And if you want to compile source to a newer version, you need to set <source>, <target>, <compilerVersion>, <fork>, and <executable> on the compiler plugin, and set <jvm> on the surefire plugin...

And now for the story...

I ran into the same problem. It turns out that compiling a previous version may not be as easy as setting <source> and <target>. My specific case is that I have a Java 1.7 JDK and I my class has an incompatibility with 1.7 (they added a new method to an interface that I am implementing). When I tried to compile it, the compiler gave me an error message stating that I had not implemented the interface method. Anyway, I tried setting the compiler 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>
    </configuration>
  </plugin>

but when I ran the build, I got the same error. So I ran maven in debug and saw this:

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

Note that the ... is put in place of actual arguments for the sake of brevity

in the output. The message starting with -d is the actual full compile argument list. So, if you remove the -nowarn flag and paste the rest after javac on the command line you can see the actual output from the compiler:

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

This prints out the handy-dandy warning bootstrap class path not set in conjunction with -source 1.6. A little googling on that turns up this article which states:

To use javac from JDK N to cross-compiler to an older platform
version, the correct practice is to:

  • Use the older -source setting.
  • Set the bootclasspath to compile against the rt.jar (or equivalent) for the older platform.

If the second step is not taken, javac will dutifully use the old
language rules combined with new libraries, which can result in class
files that do not work on the older platform since references to
non-existent methods can get included.

Now referencing the maven documentation for the compiler plugin gives:

  <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>

Which you can then combine with your earlier configuration to get:

  <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>

And now you just need to make the ${java.home} variable available to your mvn (through -D system properties, or through plain old environment variables, or you could get really fancy and stuff it in a java 6 profile in your user settings).

Now just run your build and go grab a cold beer while it chugs away...

---- EDIT ----

One last thing... Including rt.jar in your bootclasspath is always required, however, I discovered that more may be needed on a case by case basis. I had to include jce.jar (in the same directory as rt.jar) because my app was doing crypto work.

---- EDIT 2 ----

For grins, I tried it the other direction. Instead of running maven with java 7 compiling for java 6, I ran maven with java 6 compiling for java 7. The first attempt is pretty straight forward:

  <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>

Basically, I set my <source> and <target> to 1.7, but that clearly would not be enough because 6 cant compile 7 code. So back to the compiler plugin, there is actually an example page describing what needs to be done. Namely, you need to <fork> off a new process using the java 7 <executable>. So now I think I'm all set. Time to fire up the build...

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] ------------------------------------------------------------------------

What the heck is UnsupportedClassVersionError? A closer look tells us its the maven-surefire-plugin that is failing. So I try just mvn compile and sure enough I get a success as the surefire plugin never fired up. So I run mvn -X package and notice this gem:

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"

Ok, so its running java 6. Why? The documentation for surefire gives this:

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.

Since we ran mvn with a java 6 VM its forking a java 6 VM for its unit tests. So setting this option appropriately:

  <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>

And firing up the build...

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文