使用Java 7配置的Maven编译器插件,但仍可以编译Java 8代码 [英] Maven compiler plugin configured with Java 7 but still compiles Java 8 code

查看:283
本文介绍了使用Java 7配置的Maven编译器插件,但仍可以编译Java 8代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目中,我们将对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或更高".

解决方案

<source> 编译器插件的<target> 标志,该标志直接映射到 -source-target 选项(如果使用的话)是

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

  • 没有lambda表达式.在您的管道中添加一个简单的map(i -> i),然后javac将会错误,告诉您:

    -source 1.7

    中不支持

    lambda表达式

    它检测到源代码使用的特定功能在JDK 7源代码功能集中不可用.

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

    -source 1.7

    不支持

    静态接口方法调用

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

还有更多类似的东西,但这里并不是要全部描述(类型注释重复注释方法引用javac源代码中的java.net/jdk9/jdk9/langtools/file/b3d7e86a0647/src/share/classes/com/sun/tools/javac/resources/compiler.properties#l2349"rel =" noreferrer> ).总而言之,javac不会因该源代码和-source 7选项而失败.

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


回到此处的任务,实际上是使编译在此处失败.使用Maven,您有2个解决方案:

  • Fork 编译器,并进行设置指向JDK 7编译器的可执行文件.
  • 或者(首选),使用工具链的机制,以确保每个Maven插件(了解工具链)在整个构建过程中都使用此JDK(例如,Javadoc插件,它使用JDK安装的javadoc工具).

In my project, we are going to use Java 7 for maven-compiler-plugin and we assume that after Maven compile, all the code which is using Java 8 should not compile successfully.

However, in my case, there is a file using Arrays.stream(T[] array) which can be used from Java 8 and it still compiles successfully. Below is some of the pom.xml file which configure the Java version. Would you please have a look and give me any idea why my files can still compile successfully although I configure it to be Java 7?

For the pom.xml, I skip the dependencies and so on and only list the properties and the build.

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

And for the file I use a method in Java 8, the line is something like this:

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

And what I want is that since I configure the Java version to be 7 in Maven and after compile, the file which use the Java 8 should not compile successfully and show the errors like "... are allowed only at source level 1.8 or above".

解决方案

The <source> and <target> flags of the Compiler Plugin, which maps directly to the -source and -target options of the Java compiler javac (when it is the one used), are generally misunderstood.

source does not instruct javac to compile the Java source files with the specified JDK version. It instructs javac to check the version of the accepted source code, which is very different. A major version of Java sometimes brings changes to the syntax of the source code. For example, in Java 1.4, you could not write source code containing generics, like List<String>; it wasn't valid. But with Java 5, you can, which means that a new kind of Java source code was now accepted by the JDK 5 compiler. A JDK 1.4 compiler, faced with a List<String>, can only error because it doesn't know that, when the JDK 5 compiler accepts it perfectly. Setting the -source 1.4 option would tell the JDK 5 compiler to interpret the source code as JDK 1.4 source code; therefore, if that code did contain generics, it would fail, because that source code isn't valid in that version. What this also means, is that if the source code doesn't contain any Java 5 specific source code, it would compile just fine with -source 1.4.

In the example here, you have a case where the javac compiler of JDK 8 is instructed to check the source code with regard to Java 7. And actually, the line

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

does not use any Java 8 specific source code. Sure, it uses Java 8 specific classes, but the source code itself would perfectly be understandable by a JDK 7 compiler.

  • There are no lambda expressions. Add a simple map(i -> i) in your pipeline, and then javac will error, telling you:

    lambda expressions are not supported in -source 1.7

    It detected that the source code used a specific feature that isn't available in the set of the JDK 7 source code features.

  • There are no invocations of static methods on interfaces. Replace your Stream pipeline with Stream.of(arg) instead of Arrays.stream(arg). This time, you'll get an error:

    static interface method invocations are not supported in -source 1.7

    Arrays is not an interface, so invoking a static method stream on that class is perfectly valid JDK 7 source code. However, Stream is an interface (which is, of course, known to the JDK 8 compiler you're using), and, before Java 8, interfaces couldn't contain static methods. As such, it isn't valid Java 7 source code.

There are more like that, but the point isn't to describe them all here (type annotations, repeated annotations, method references, intersection types in cast... you can see all of them in javac source code for example). All in all, there is no reason for javac to fail with that source code and the -source 7 option.

target is another beast entirely; this isn't the issue here, so suffice it to say that it instructs javac to generate byte code that targets the specified version the VM. It does not ensure in any way, that the byte code produced will actually run with said version of the VM. If you want to ensure that, the -bootclasspath option is to be used.


Coming back to the task at hand here, which is actually to make compilation fail here. With Maven, you have 2 solutions:

  • Fork the compiler, and set an executable pointing to the JDK 7 compiler.
  • Or (preferred), use the mechanism of toolchains, to ensure that every Maven plugins (aware of toolchains) use this JDK throughout the build (i.e. the Javadoc plugin for example, which uses the javadoc tool of the JDK installation).

这篇关于使用Java 7配置的Maven编译器插件,但仍可以编译Java 8代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆