Требуемая версия Java Maven Dependency?

Я разработал и построил свое приложение Java с помощью Maven. Мне нужно поддерживать Java 1.6, поэтому я использую следующие свойства:

<maven.compiler.target>1.6</maven.compiler.target>
<maven.compiler.source>1.6</maven.compiler.source>

Тем не менее, когда я запускаю приложение, я получаю сообщение об ошибке "Unsupported major.minor version", и я подозреваю, что один из моих баров с зависимостями скомпилирован с версией Java, более новой, чем тот, который мне нужно поддерживать.

Мои вопросы:

  • Возможно ли это? Я думал, что Maven позаботится об этих проблемах с версиями зависимостей.

  • Есть ли простой способ узнать малую/основную версию всех моих зависимостей? (Было бы здорово, если бы это можно было показать при выполнении mvn dependency:tree, например.)

Ответ 1

Проблема заключается в том, что каждая зависимая (поддерживающая) может решить, какая из них использует java-версию для компиляции (1.5, 1.6, 1.7, 1.8 и т.д.), поэтому это не разрешимо через Maven. Но вы можете убедиться, что не используете зависимости, которые используют другую версию Java, чем вам нравится.

Это можно выполнить, используя Maven Enforcer Plugin с помощью extra-enforcer-rules:

<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-enforcer-plugin</artifactId>
        <version>1.4.1</version> <!-- find the latest version at http://maven.apache.org/plugins/maven-enforcer-plugin/ -->
        <executions>
          <execution>
            <id>enforce-bytecode-version</id>
            <goals>
              <goal>enforce</goal>
            </goals>
            <configuration>
              <rules>
                <enforceBytecodeVersion>
                  <maxJdkVersion>1.6</maxJdkVersion>
                  <excludes>
                    <exclude>org.mindrot:jbcrypt</exclude>
                  </excludes>
                </enforceBytecodeVersion>
              </rules>
              <fail>true</fail>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>extra-enforcer-rules</artifactId>
            <version>1.0-beta-5</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

Это сломает вашу сборку, если у вас есть зависимость, которая скомпилирована с другой версией JDK, чем вы хотите.

Ответ 2

Чтобы ответить на два вопроса:

Да, это возможно. Рассматривая docs, свойства <maven.compiler.target> и <maven.compiler.source> просто указывают Maven, какую версию javac использовать для компиляции > ваш. И я цитирую, для вашей справки:

Примечание. Простота установки целевого параметра не гарантирует, что ваш код действительно работает на JRE с указанной версией. Ловушка непреднамеренное использование API, которые существуют только в более поздних JRE, которые чтобы ваш код не работал во время выполнения с ошибкой привязки. Чтобы избежать этого вы можете настроить путь к классу загрузки компилятора, чтобы он соответствовал целевой JRE или использовать плагин Anaven Sniffer Maven для проверки вашего код не использует непреднамеренные API.

магическое число после ошибки Unsupported major.minor version фактически сообщает версии JRE, что файл класса совместим с:

J2SE 8 = 52,
J2SE 7 = 51,
J2SE 6.0 = 50,
J2SE 5.0 = 49,
JDK 1.4 = 48,
JDK 1.3 = 47,
JDK 1.2 = 46,
JDK 1.1 = 45

Я не знаю, есть ли простой способ рассказать основную/младшую версию ВСЕХ зависимостей (и транзитивных зависимостей) в проекте.

ОБНОВЛЕНИЕ: Хотя я еще не использовал его раньше, мне интересно, что плагин Animal Sniffer Maven поможет вынюхать основную/второстепенную версию ваших зависимостей.