--- --- SPOILER ALERT
La respuesta corta es que con el fin de compilar código fuente de una versión anterior, es necesario proporcionar tanto la opción -source
así como la -bootclasspath
. Ver this article. Y si se desea compilar fuente a una nueva versión, es necesario establecer <source>
, <target>
, <compilerVersion>
, <fork>
, y <executable>
en el plugin del compilador, y establecer <jvm>
en el plugin segura ...
y ahora para la historia ...
Me encontré con el mismo problema. Resulta que compilar una versión anterior puede no ser tan fácil como configurar <source>
y <target>
. Mi caso específico es que tengo un Java 1.7 JDK y que mi clase tiene una incompatibilidad con 1.7 (agregaron un nuevo método a una interfaz que estoy implementando). Cuando traté de compilarlo, el compilador me dio un mensaje de error que decía que no había implementado el método de interfaz. De todos modos, he intentado configurar el plugin del compilador:
<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>
pero cuando me encontré con la construcción, me dieron el mismo error. Así que corrí experto en depuración y vi esto:
[INFO] [DEBUG] Command line options:
[INFO] [DEBUG] -d C:\... -nowarn -target 1.6 -source 1.6 -encoding UTF-8
Tenga en cuenta que la ... se pone en su lugar de argumentos reales en aras de la brevedad
en la salida. El mensaje que comienza con -d
es la lista de argumentos de compilación completa real. Por lo tanto, si se quita la bandera -nowarn
y pegar el resto después de javac
en la línea de comandos se puede ver la salida real del compilador:
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
Esto muestra la advertencia ruta de clase arranque práctico-excelente no ocupa conjunción con -fuente 1.6. Un poco de googling en que se vuelve a this article que establece:
To use javac from JDK N to cross-compiler to an older platform version, the correct practice is to:
- Use the older -source setting.
- Set the bootclasspath to compile against the rt.jar (or equivalent) for the older platform.
If the second step is not taken, javac will dutifully use the old language rules combined with new libraries, which can result in class files that do not work on the older platform since references to non-existent methods can get included.
ahora referencia a the maven documentation for the compiler plugin da:
<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>
que luego se puede combinar con la configuración anterior para obtener:
<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>
Y ahora solo necesita hacer que la variable ${java.home}
esté disponible para su mvn (a través de las propiedades del sistema -D oa través de antiguas variables de entorno, o puede ser realmente elegante y rellenarlo en un perfil java 6 en su configuración de usuario).
Ahora acaba de ejecutar su construcción y ir a tomar una cerveza fría mientras resopla distancia ...
---- ---- EDITAR
Una última cosa ... Incluyendo en rt.jar su bootclasspath es siempre se requiere, sin embargo, descubrí que se pueden necesitar más caso por caso. Tuve que incluir jce.jar (en el mismo directorio que rt.jar) porque mi aplicación estaba haciendo trabajo de cifrado.
---- EDIT 2 ----
para las muecas, yo lo probé la otra dirección. En lugar de correr experto con Java 7 compilar para Java 6, me encontré con la experta en Java 6 compilar para Java 7. El primer intento es bastante sencillo:
<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>
Básicamente, me puse mi <source>
y <target>
a 1,7, pero eso claramente no sería suficiente porque 6 no pueden compilar el código 7. Volviendo al plugin del compilador, en realidad hay an example page que describe lo que se debe hacer.A saber, necesita <fork>
de un nuevo proceso usando java 7 <executable>
. Entonces ahora creo que estoy listo. Es hora de encender la construcción ...
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] ------------------------------------------------------------------------
¿Qué demonios es UnsupportedClassVersionError? Una mirada más cercana nos dice que es el plugin maven-surefire que está fallando. Así que intento solo mvn compile
y con seguridad obtengo un éxito ya que el plugin surefire nunca se activó. Así que corro mvn -X package
y cuenta de esta joya:
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"
Ok, por lo que su ejecución Java 6. ¿Por qué? La documentación para el éxito seguro da esto:
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.
Como nos encontramos con un mvn java 6 VM su bifurcar un java 6 VM para sus pruebas de unidad. Por lo que establecer esta opción apropiada:
<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>
Y encendiendo la acumulación ...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Si intenta ejecutar los archivos liberados en 1.5, ¿se ejecutan en 1.5? ¿O recibe una excepción jar no válida/jar dañado, diciéndole que probablemente fueron compilados en una versión posterior? – aperkins
Tanto la instantánea como los archivos de liberación parecen estar funcionando, ejecutándose en 1.5. Todavía no recibo ningún error, pero no entiendo por qué las clases tienen un tamaño diferente. Solo espero que algo no vaya a saltar sobre mí cuando llegue a producción. – IceGras
@IceGras, podría ser peligroso, explico por qué en mi respuesta a continuación ... En resumen, las referencias a métodos inexistentes pueden incluirse_ – Lucas