【问题标题】:Maven compiler plugin configured with Java 7 but still compiles Java 8 code使用 Java 7 配置的 Maven 编译器插件,但仍编译 Java 8 代码
【发布时间】:2017-04-20 07:19:57
【问题描述】:

在我的项目中,我们将为maven-compiler-plugin 使用Java 7,并且我们假设在Maven 编译之后,所有使用Java 8 的代码都不应编译成功。

但是,就我而言,有一个使用 Arrays.stream(T[] array) 的文件可以从 Java 8 中使用,并且它仍然可以成功编译。下面是一些配置 Java 版本的pom.xml 文件。请您看看并告诉我为什么我的文件仍然可以成功编译,尽管我将它配置为 Java 7?

对于pom.xml,我跳过依赖等,只列出属性和构建。

<properties>
    <java.version>1.7</java.version>
</properties>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compiler-plugin.version}</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
            </configuration>
        </plugin>
    </plugins>
</build> 

对于我使用 Java 8 中的方法的文件,该行是这样的:

buffer.append(Arrays.stream(arg).collect(Collectors.joining("/")));

而我想要的是,由于我在 Maven 中将 Java 版本配置为 7,并且在编译后,使用 Java 8 的文件不应成功编译并显示诸如“...”之类的错误仅在源代码级别允许1.8以上”。

【问题讨论】:

    标签: java eclipse maven maven-compiler-plugin


    【解决方案1】:

    编译器插件的&lt;source&gt;&lt;target&gt; 标志直接映射到Java 编译器javac-source and -target 选项(当它被使用时)是generally misunderstood

    source 不指示javac 编译具有指定JDK 版本的Java 源文件。它指示javac 检查接受的源代码的版本,这是非常不同的。 Java 的主要版本有时会更改源代码的语法。例如,在 Java 1.4 中,您不能编写包含泛型的源代码,例如 List&lt;String&gt;;这是无效的。但是使用 Java 5,您可以,这意味着 JDK 5 编译器现在接受了一种新的 Java 源代码。 JDK 1.4 编译器面对List&lt;String&gt;,只会出错,因为它不知道,当 JDK 5 编译器完全接受它时。设置-source 1.4 选项将告诉JDK 5 编译器将源代码解释为JDK 1.4 源代码;因此,如果该代码确实包含泛型,它将失败,因为该源代码在该版本中无效。这也意味着,如果源代码不包含任何 Java 5 特定的源代码,它可以用-source 1.4 编译。

    在此处的示例中,您有一个情况,即指示 JDK 8 的 javac 编译器检查 Java 7 的源代码。实际上,该行

    buffer.append(Arrays.stream(arg).collect(Collectors.joining("/")));
    

    不使用任何 Java 8 特定的源代码。当然,它使用 Java 8 特定的,但源代码本身完全可以被 JDK 7 编译器理解。

    • 没有 lambda 表达式。在你的管道中添加一个简单的map(i -&gt; i),然后javac会报错,告诉你:

      -source 1.7 不支持 lambda 表达式

      它检测到源代码使用了 JDK 7 源代码特性集中不可用的特定特性。

    • 接口上没有静态方法的调用。将您的 Stream 管道替换为 Stream.of(arg) 而不是 Arrays.stream(arg)。这一次,你会得到一个错误:

      -source 1.7 不支持静态接口方法调用

      Arrays 不是接口,因此在该类上调用静态方法 stream 是完全有效的 JDK 7 源代码。但是,Stream 是一个接口(当然,您正在使用的 JDK 8 编译器知道它),并且在 Java 8 之前,接口不能包含静态方法。因此,它不是有效的 Java 7 源代码。

    还有更多类似的,但重点不是在这里全部描述(type annotationsrepeated annotationsmethod referencesintersection types in cast...你可以看到所有这些in javac source code for example)。总而言之,javac 没有理由因为该源代码和 -source 7 选项而失败。

    target 完全是另一只野兽;这不是这里的问题,所以只要说它指示javac 生成针对VM 指定版本的字节码就足够了。它不以任何方式确保生成的字节码将实际与所述版本的 VM 一起运行。如果您想确保这一点,请使用-bootclasspath 选项。


    回到这里手头的任务,实际上是让编译失败。使用 Maven,you have 2 solutions

    • Fork 编译器,并设置一个 executable 指向 JDK 7 编译器。
    • 或者(首选),使用toolchains的机制,以确保每个Maven插件(知道工具链)在整个构建过程中都使用这个JDK(例如Javadoc插件,它使用了javadoc工具JDK 安装)。

    【讨论】:

    • 非常感谢!我对此有了更多的理解!真的很棒的解释!
    【解决方案2】:

    我同意@Tunaki 所说的一切。如果您决定使用选项一,这里有一个来自 Maven 文档的配置示例,可以帮助您。

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven-compiler-plugin.version}</version>
        <configuration>
          <verbose>true</verbose>
          <fork>true</fork>
          <executable><!-- path-to-javac --></executable>
          <compilerVersion>1.7</compilerVersion>
          <source>${java.version}</source>
          <target>${java.version}</target>
        </configuration>
      </plugin>
    </plugins>
    

    【讨论】:

      猜你喜欢
      • 2012-12-12
      • 2016-10-28
      • 1970-01-01
      • 2013-10-10
      • 1970-01-01
      • 2017-04-09
      • 2014-07-25
      • 2012-11-10
      • 2014-09-26
      相关资源
      最近更新 更多