在 Maven 构建中使用 Eclipse Java 编译器 (ecj)

Using Eclipse Java Compiler (ecj) in maven builds

Eclipse 使用它自己的编译器 (ECJ) 来编译 Java 代码。调试使用 Eclipse 编译的程序更容易,因为可以立即应用简单的代码更改(通过热代码替换)。

另一方面,Maven 使用(默认)oracle JDK,它生成不同的字节代码,防止在 Eclipse 调试会话中进行热代码替换。

因此,如果我打算调试程序,我想在我的 Maven 构建中使用 Eclipse ECJ 编译器。对我来说一个方便的方法是 "ecj" 个人资料:

也可以在 settings.xml 甚至 Eclipse 项目属性中指定配置文件激活。

我的问题是:

  1. 这是正确的方法吗?
  2. 如何配置?
  3. maven 工具链可以用于此吗?

It is possible to change the default javac compiler that is used by the maven-compiler-plugin. The Eclipse compiler is bundled in the artifact plexus-compiler-eclipse and it is declared by setting the compilerId maven-compiler-plugin 属性为 eclipse.

如果您想为 custom profile 激活此更改,您可以进行以下配置:

<profile>
  <id>ecj</id>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.0</version>
        <configuration>
          <compilerId>eclipse</compilerId>
        </configuration>
        <dependencies>
          <dependency>
            <groupId>org.codehaus.plexus</groupId>
            <artifactId>plexus-compiler-eclipse</artifactId>
            <version>2.8.1</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>
</profile>

插件在Plexus Compiler依赖后plexus-compiler GitHub repository. Version 2.8.1 uses 3.11.1.v20150902-1521 of JDT, although you could use your own version by adding a dependency on org.eclipse.tycho:org.eclipse.jdt.core维护

Eclipse Java 编译器 (ecj) 比标准 javac 编译器有很多优点。它速度很快,并且可以配置更多的警告和错误,从而提高代码质量。编译器中最有趣的事情之一是添加了 null types inside the compiler:通过使用 @Nullable 和 @NotNull 注释对代码进行注释,您可以强制 Eclipse 编译器在编译时检查空访问,而不是 运行时间。当严格应用时,这会教会您以更安全的方式编写代码(通过防止空值),并且它可以防止在测试或生产期间出现 NPE 异常。

在Maven 中使用Eclipse Compiler 并不难,但是互联网上有很多错误信息和旧信息,造成很多混乱。我希望这有助于解决问题。

要让 Maven 使用 ecj 编译器,您只需要使用 plexus-compiler-eclipse 插件即可。典型配置如下:

<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.7.0</version>
            <configuration>
                <compilerId>eclipse</compilerId>
                <source>${source.jdk.version}</source>
                <target>${target.jdk.version}</target>
                <!-- Passing arguments is a trainwreck, see https://issues.apache.org/jira/browse/MCOMPILER-123 -->
                <compilerArguments>
                    <properties>${project.basedir}/.settings/org.eclipse.jdt.core.prefs</properties>
                </compilerArguments>
                <showWarnings>true</showWarnings>
                <showDeprecation>true</showDeprecation>
            </configuration>

            <dependencies>
                <dependency>
                    <groupId>org.codehaus.plexus</groupId>
                    <artifactId>plexus-compiler-eclipse</artifactId>
                    <version>2.8.3</version>
                </dependency>

                <dependency>
                    <groupId>org.eclipse.jdt</groupId>
                    <artifactId>ecj</artifactId>
                    <version>3.13.101</version>
                </dependency>
            </dependencies>
        </plugin>
</pluginManagement>

将此部分放入 parent/root pom 的 pluginManagement 或构建部分。

现在让我们解释一下不同的部分;)

maven-compiler-plugin 需要是最新版本。 source 和 target 参数定义 java 用于源代码和字节码的版本,通常是相同的。

将参数传递给编译器完全是一件麻烦事。请参阅下面的单独部分。在此示例中,我使用了属性设置,它允许我提供有关编译时我希望出现的错误和警告的详细设置。通过在参数中使用 ${project.basedir} 变量,我为每个项目设置了这些设置:每个项目都需要有一个 .settings/org.eclipse.jdt.core.prefs 文件(这是幸运的机会Eclipse IDE 保留其编译器设置的位置)。

对 plexus-codehaus-eclipse 的依赖定义了知道如何 运行 Eclipse 编译器的插件。 2.8.3 版本是撰写本文时的最新版本,但该版本存在一些问题。 2.8.4 版应该带有一个重写的编译器接口,它修复了很多问题,但在撰写本文时该版本仍在开发中。您可以 find details on the plugin here,因此可以在新的 releases/code 更改中跟进进度。

另一个重要的依赖项是 org.eclipse.jdt:ecj 依赖项:它指定要使用的 ecj 编译器的确切版本。你应该总是指定它,否则当插件决定在你有一个大版本前一天使用另一个版本的编译器时,构建稳定性会受到影响;)用于 ecj 编译器的版本号有点问题。您或许可以从 the list of releases and then check this maven repository for something that looks like it. But this repository only contains the older versions. When you need a more recent release you should apparently look here at this one - this is where Eclipse currently pushes its versions 中找到版本号。这个较新的存储库取消了早期版本中易于识别的版本号;如上所示,它使用像 3.1x.x 这样的版本号。 Eclipse 通常每年发布一次主要版本,中间还会发布一到两个修复版本。 3.13.x 数字中的第二部分对应于 Eclipse 平台项目内部用于发布的内部版本控制。很难通过列表获得,但至少这些是已知的:

Version    Eclipse Release      Compiler Version
3.13.0     Oxygen Release       4.7
3.13.50    Oxygen 1a            4.7.1a
3.13.100   Oxygen R2            4.7.2

版本总是以 3 开头,13 或多或少是 "year" 的版本。所以当 13 是氧气 (2017, 4.7) 时,14 可能是光子 (2018, 4.8)。

plexus-compiler-eclipse 插件版本:2.8.4 之前

plexus-compiler-plugin 2.8.4 之前的版本使用内部 API 来启动 Eclipse 编译器。这会导致很多事情无法正常工作,例如这个内部 API 不会解释 ecj 编译器的常用命令行参数。这使得它很难使用,而且有些东西不受支持。以下是限制列表:

  • 注释处理未实现。任何配置都会被忽略。

  • 使用 标记添加特定参数很难,因为实施存在多个问题:

  • 编译器 mojo 似乎为此处输入的所有参数添加破折号。但是,此版本插件使用的内部 API 需要不带破折号的参数。所以插件再次删除它们。 由于这里的参数并不是真正的命令行 ecj 参数,因此很难知道使用哪些参数:查看 Eclipse 源代码中的 Compiler.java class 和 CompilerOptions.java classes了解详情。

  • 插件确实在那里接受一些参数,但这些参数由插件本身解释,然后 "translated" 到内部 api.

此插件在 > 标签中接受以下参数:

  • filename:定义将传递给编译器的 -properties 参数的属性文件。通过查看 Eclipse 项目中的文件 .settings/org.eclipse.jdt.core.prefs 可以找到此文件格式的示例:此文件 stres 编译器的配置。它包含警告、错误和信息性消息的设置以及编译器合规性设置。

  • 随便。当这有效时,插件将忽略编译器生成的任何错误并将它们报告为警告。当然编译仍然失败,所以根据错误,.class 文件可能是 written/updated 或不是。这由插件本身处理:它只是将所有错误更改为警告并告诉世界编译有效。

自 2.8.4

plexus-compiler-eclipse 插件的 2.8.4 版已大部分重写。它现在使用 ECJ 编译器的 public API 或多或少是 ECJ 编译器本身。例如,这意味着 ECJ 可以做的所有事情(比如注释处理)插件现在也可以做,并且在标签中输入的参数现在传递给编译器,这意味着您应该能够使用 ecj's help page 来查找要添加的有趣参数。

与之前的版本一样,这个版本也要求您从所有参数名称中删除“-”;在将参数名称添加到 ecj 命令行之前,破折号会再次自动添加。

该版本支持Maven定义的注解处理;通过将所需的部分添加到编译 blob,您可以拥有注释处理器 运行。例如:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${maven-compiler-plugin.version}</version>
    <configuration>
        <annotationProcessors>
            <annotationProcessor>db.annotationprocessing.EntityAnnotationProcessor</annotationProcessor>
        </annotationProcessors>
        <annotationProcessorPaths>
            <dependency>
                <groupId>to.etc.domui</groupId>
                <artifactId>property-annotations-processor</artifactId>
                <version>1.2-SNAPSHOT</version>
            </dependency>
        </annotationProcessorPaths>
    </configuration>

    <dependencies>
        <dependency>
            <groupId>to.etc.domui</groupId>
            <artifactId>property-annotations-processor</artifactId>
            <version>1.2-SNAPSHOT</version>
        </dependency>
    </dependencies>
</plugin>

这部分可能看起来不完整,因为根本没有引用 plexus-compiler-eclipse 插件,但请记住,在 Maven 中,配置继承:在这种情况下,父 POM 包含上面的部分,这只是添加仅针对此 POM 项目的一些配置。