Плагин компилятора Maven, настроенный на Java 7, но по-прежнему компилирующий код Java 8

В моем проекте мы собираемся использовать Java 7 для maven-compiler-plugin и предполагаем, что после компиляции Maven весь код, использующий Java 8, не должен успешно компилироваться.

Однако в моем случае есть файл, использующий Arrays.stream(T[] array), который можно использовать из Java 8, и он все еще успешно компилируется. Ниже приведены некоторые файлы pom.xml, которые настраивают версию Java. Не могли бы вы взглянуть и дать мне понять, почему мои файлы все еще могут успешно компилироваться, хотя я настроил их на 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("/")));

И я хочу, чтобы, поскольку я настраиваю версию Java на 7 в Maven и после компиляции, файл, использующий Java 8, не должен успешно компилироваться и показывать такие ошибки, как «... разрешены только на уровне исходного кода 1.8 или выше. ".


person TryMyBest    schedule 05.12.2016    source источник


Ответы (2)


<source> и <target> подключаемого модуля компилятора, который напрямую сопоставляется с -source и -target компилятора Java javac ( когда он используется), обычно понимают неправильно.

source не указывает javac компилировать исходные файлы Java с указанной версией JDK. Он указывает javac проверить версию принятого исходного кода, которая сильно отличается. Основная версия Java иногда вносит изменения в синтаксис исходного кода. Например, в Java 1.4 вы не могли писать исходный код, содержащий дженерики, такие как List<String>; это было недействительно. Но с Java 5 это возможно, а это значит, что теперь компилятор JDK 5 принимает исходный код Java нового типа. Компилятор JDK 1.4, столкнувшись с List<String>, может ошибаться только потому, что не знает об этом, тогда как компилятор JDK 5 прекрасно его принимает. Установка параметра -source 1.4 указывает компилятору JDK 5 интерпретировать исходный код как исходный код JDK 1.4; поэтому, если бы этот код действительно содержал дженерики, он потерпел бы неудачу, потому что этот исходный код недействителен в этой версии. Это также означает, что если исходный код не содержит какого-либо исходного кода, специфичного для Java 5, он прекрасно скомпилируется с -source 1.4.

В приведенном здесь примере у вас есть случай, когда javac компилятор JDK 8 получает указание проверить исходный код в отношении Java 7. И на самом деле, строка

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

не использует какой-либо специфичный для Java 8 исходный код. Конечно, он использует специфичные для Java 8 классы, но сам исходный код вполне понятен компилятору JDK 7.

  • #P5# <блочная цитата> #P6# #P7#
  • #P8# <блочная цитата> #P9# #P10#

Есть и другие подобные, но цель не в том, чтобы описать их все здесь (введите аннотации, повторяющиеся аннотации, ссылки на методы, типы пересечений в приведении... вы можете увидеть их все в javac исходном коде, например) . В общем, нет никаких причин, по которым javac не сможет работать с этим исходным кодом и параметром -source 7.

target совсем другой зверь; здесь проблема не в этом, поэтому достаточно сказать, что он указывает javac генерировать байтовый код, предназначенный для указанной версии виртуальной машины. Это никоим образом не гарантирует, что созданный байт-код действительно будет работать с указанной версией виртуальной машины. Если вы хотите убедиться в этом, используйте опцию -bootclasspath.


Возвращаясь к поставленной здесь задаче, которая на самом деле состоит в том, чтобы сделать здесь неудачную компиляцию. С Maven у вас есть 2 решения:

  • разветвить компилятор и установить executable, указывающий на компилятор JDK 7.
  • Или (предпочтительнее) использовать механизм цепочек инструментов, чтобы обеспечить что все плагины Maven (осведомленные о цепочках инструментов) используют этот JDK на протяжении всей сборки (например, плагин Javadoc, который использует инструмент javadoc установки JDK).
person Tunaki    schedule 05.12.2016
comment
Большое спасибо! Я получил больше понимания для этого! Действительно классное объяснение! - person TryMyBest; 08.12.2016

Я согласен со всем, что заявляет @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>
person M. Rizzo    schedule 05.12.2016