Ответ 1
--- ПРЕДУПРЕЖДЕНИЕ SPOILER ---
Короткий ответ заключается в том, что для того, чтобы скомпилировать исходный код для более старой версии, вам необходимо указать как параметр -source
так и -bootclasspath
. См. в этой статье. И если вы хотите скомпилировать исходный код для более новой версии, вам нужно установить <source>
, <target>
, <compilerVersion>
, <fork>
и <executable>
в плагине компилятора и установить <jvm>
в плагин surefire...
И теперь для истории...
Я столкнулся с той же проблемой. Оказывается, компиляция предыдущей версии может быть не такой простой, как установка <source>
и <target>
. В моем конкретном случае у меня есть Java 1.7 JDK, и у меня класс несовместим с 1.7 (они добавили новый метод для интерфейса, который я реализую). Когда я попытался скомпилировать его, компилятор дал мне сообщение об ошибке, в котором говорилось, что я не реализовал метод интерфейса. Во всяком случае, я попытался установить плагин компилятора:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
но когда я запустил сборку, я получил ту же ошибку. Итак, я побежал maven в отладке и увидел это:
[INFO] [DEBUG] Command line options:
[INFO] [DEBUG] -d C:\... -nowarn -target 1.6 -source 1.6 -encoding UTF-8
Обратите внимание, что... для краткости вместо фактических аргументов вместо
на выходе. Сообщение, начинающееся с -d
, является фактическим полным списком параметров компиляции. Итак, если вы удалите флаг -nowarn
и вставьте остальные после javac
в командной строке, вы увидите фактический вывод компилятора:
javac -d C:\... -target 1.6 -source 1.6 -encoding UTF-8
warning: [options] bootstrap class path not set in conjunction with -source 1.6
Это выводит путь к классу bootstrap, который не задан вместе с -source 1.6. Немного googling на этом появляется в этой статье, в которой говорится:
Использовать javac из JDK N для перекрестного компилятора на более старую платформу версии, правильная практика заключается в следующем:
- Используйте параметр old-source.
- Установите bootclasspath для компиляции с rt.jar(или эквивалентом) для старой платформы.
Если второй шаг не выполняется, javac будет покорно использовать старый языковые правила в сочетании с новыми библиотеками, что может привести к классу файлы, которые не работают на старой платформе, поскольку ссылки на несуществующие методы могут быть включены.
Теперь ссылаясь на документацию maven для плагина компилятора, вы получите:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}\lib\rt.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
Что вы можете комбинировать с более ранней конфигурацией, чтобы получить:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
<bootclasspath>${java.home}\lib\rt.jar</bootclasspath>
</configuration>
</plugin>
И теперь вам просто нужно сделать переменную ${java.home}
доступной для ваших свойств mvn (через -D или через обычные старые переменные окружения, или вы можете получить действительно причудливые вещи и наполнить их в профиле java 6 у своего пользователя настройки).
Теперь просто запустите свою сборку и поймите, возьмите холодное пиво, пока оно пробивается...
---- EDIT ----
Последнее:... В том числе rt.jar в вашем bootclasspath всегда требуется, однако, я обнаружил, что больше может понадобиться в каждом конкретном случае. Я должен был включить jce.jar(в том же каталоге, что и rt.jar), потому что мое приложение выполняло криптографическую работу.
---- ИЗМЕНИТЬ 2 ----
Для усмешек я попробовал это в другом направлении. Вместо запуска maven с компиляцией java 7 для java 6 я запускал maven с компиляцией java 6 для java 7. Первая попытка довольно проста:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<fork>true</fork>
<verbose>true</verbose>
<compilerVersion>1.7</compilerVersion>
<executable>${JAVA_7_HOME}/bin/javac</executable>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
В принципе, я установил мои <source>
и <target>
в 1.7, но этого явно не хватило бы потому, что 6 не удалось скомпилировать код 7. Итак, вернемся к плагину компилятора, на самом деле примерная страница, описывающая, что нужно делать. А именно, вам нужно <fork>
отключить новый процесс, используя java 7 <executable>
. Так что теперь я думаю, что все готово. Время для запуска сборки...
C:\Projects\my-project>mvn package
...
Caused by: java.lang.UnsupportedClassVersionError: mypackage.StupidTest : Unsup
ported major.minor version 51.0
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
Какая черта UnsupportedClassVersionError? Более пристальный взгляд говорит нам о своем плагине maven-surefire, который терпит неудачу. Поэтому я стараюсь просто mvn compile
и, конечно же, добился успеха, так как плагин surefire никогда не запускался. Поэтому я запускаю mvn -X package
и замечаю этот камень:
Forking command line: cmd.exe /X /C ""C:\Program Files\Java\jdk1.6.0_29\jre\bin\
java" -jar C:\Projects\my-project\target\surefire\surefirebooter2373372991878002
398.jar C:\Projects\my-project\target\surefire\surefire1861974777102399530tmp C:
\Projects\my-project\target\surefire\surefire4120025668267754796tmp"
Хорошо, так работает java 6. Почему? Документация для surefire дает следующее:
jvm:
Option to specify the jvm (or path to the java executable) to use with the forking
options. For the default, the jvm will be a new instance of the same VM as the one
used to run Maven. JVM settings are not inherited from MAVEN_OPTS.
Так как мы запускали mvn с java 6 VM, он разворачивал java 6 VM для своих модульных тестов. Поэтому установите этот параметр соответствующим образом:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<jvm>${JAVA_7_HOME}/bin/java</jvm>
</configuration>
</plugin>
И запуск сборки...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------