test reports pom plugin are java eclipse maven intellij-idea maven-compiler-plugin

reports - Configuración de la versión Java de Maven ignorada por Eclipse/Idea



surefire pom (1)

Yo tengo:

<build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </pluginManagement> </build>

Sin embargo, no tengo problemas para declarar:

public enum DirectoryWatchService { INSTANCE; private java.util.Optional<String> test; private java.nio.file.Files files; }

Eclipse no molesta. IntelliJ tampoco. Incluso Maven no se molesta. Incluso puedo hacer un paquete limpio mvn . Construye la maldita cosa sin ninguna advertencia.


Estás llegando al malentendido de compilación cruzada de target opciones de source / target . Usando una versión principal en tu classpath (JDK 7 u 8) pero deseando compilar contra una versión menor (6 en tu caso).
La compilación estará bien, pero tendrá errores en tiempo de ejecución (es decir, NoClassDefFoundError o NoSuchMethodError , probablemente también el LinkageError más genérico).

Usando el source / target , el compilador de Java puede usarse como un compilador cruzado para producir archivos de clase ejecutables en JDK que implementan una versión anterior de la especificación Java SE.

La creencia común es que usar dos opciones de compilación sería suficiente. Sin embargo, la opción de source especifica contra qué versión estamos compilando, mientras que la opción de target especifica la versión de Java más baja para admitir.

El compilador funciona en la generación de bytecode y la source y el target se utilizan para generar bytecode compatible durante la compilación cruzada. Sin embargo, el compilador no maneja las API de Java (se proporcionan como parte de la instalación de JDK, el famoso archivo rt.jar ). El compilador no tiene ningún conocimiento de API, solo compila contra el rt.jar actual. Por lo tanto, al compilar con target=1.6 utilizando JDK 1.7, el compilador seguirá apuntando a JDK 7 rt.jar .

Entonces, ¿cómo podemos tener una compilación cruzada correcta?

Desde JDK 7, javac imprime una advertencia en caso de que el source / target no esté en combinación con la opción bootclasspath . La opción bootclasspath es la opción clave en estos casos para apuntar al rt.jar de la versión de Java de destino deseada (por lo tanto, debe tener el JDK de destino instalado en su máquina). Como tal, javac compilará efectivamente contra la buena API de Java.

¡Pero eso puede no ser suficiente!

No todas las API de Java provienen de rt.jar . La carpeta lib/ext proporciona otras clases. Para eso se usa una opción adicional de javac , extdirs . De documentos oficiales de Oracle

Si realiza una compilación cruzada (compilando clases contra bootstrap y clases de extensión de una implementación de plataforma Java diferente), esta opción especifica los directorios que contienen las clases de extensión.

Por lo tanto, incluso usando las opciones source / target y bootclasspath , aún podemos perder algo durante la compilación cruzada, como también se explica en el ejemplo oficial que viene con la documentación de javac.

Java Platform JDK de Java también compilaría por defecto contra sus propias clases de bootstrap, por lo que debemos decirle a javac que compile contra JDK 1.5. Hacemos esto con -bootclasspath y -extdirs. No hacerlo puede permitir la compilación contra una API de plataforma Java que no estaría presente en una máquina virtual 1.5 y fallaría en tiempo de ejecución.

Pero ... aún puede no ser suficiente!

De la documentation oficial de Oracle

Incluso cuando bootclasspath y -source / -target están configurados adecuadamente para la compilación cruzada, los contratos internos del compilador, como la forma en que se compilan las clases internas anónimas, pueden diferir entre, por ejemplo, javac en JDK 1.4.2 y javac en JDK 6 corriendo con la opción -target 1.4.

La solución sugerida (de la documentación documentation )

La forma más confiable de producir archivos de clase que funcionarán en un JDK particular y más tarde es compilar los archivos fuente utilizando el JDK de interés más antiguo. Salvo eso, el bootclasspath debe estar configurado para una compilación cruzada robusta a un JDK anterior.

Entonces, ¿esto realmente no es posible?

Spring 4 actualmente es compatible con Java 6, 7 y 8 . Incluso usando las características y API de Java 7 y Java 8. ¿Cómo puede ser compatible con Java 7 y 8?

Spring hace uso de la flexibilidad source / target y bootclasspath . Spring 4 siempre compila con source / target para Java 6, de modo que el source bytes aún puede ejecutarse bajo JRE 6. Por lo tanto, no se utilizan características de lenguaje Java 7/8: la sintaxis mantiene el nivel de Java 6.
¡Pero también usa Java 7 y Java 8 API! Por lo tanto, la opción bootclasspath no se usa. Opcional, se utilizan Stream y muchas otras API de Java 8. Luego inyecta beans dependiendo de la API de Java 7 o Java 8 solo cuando se detectan JRE 7/8 en tiempo de ejecución: ¡enfoque inteligente!

Pero, ¿cómo asegura Spring la compatibilidad de la API entonces?

Usando el complemento Maven Animal Sniffer .
Este complemento verifica si su aplicación es compatible con API con una versión específica de Java. Se llama sniffer de animales porque Sun tradicionalmente nombra las diferentes versiones de Java después de diferentes animales (Java 4 = Merlin (pájaro), Java 5 = Tigre, Java 6 = Mustang (caballo), Java 7 = Delfín, Java 8 = ningún animal).

Puede agregar lo siguiente a su archivo POM:

<build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>animal-sniffer-maven-plugin</artifactId> <version>1.14</version> <configuration> <signature> <groupId>org.codehaus.mojo.signature</groupId> <artifactId>java16</artifactId> <version>1.0</version> </signature> </configuration> <executions> <execution> <id>ensure-java-1.6-class-library</id> <phase>verify</phase> <goals> <goal>check</goal> </goals> </execution> </executions> </plugin> </plugins> </build>

Y la compilación fallará tan pronto como use JDK 7 API mientras desea usar solo JDK 6 API.

Este uso también se recomienda en la página oficial de source / target del maven-compiler-plugin

Nota : el simple hecho de configurar la opción de target no garantiza que su código realmente se ejecute en un JRE con la versión especificada. La trampa es el uso no intencionado de API que solo existen en JRE posteriores, lo que haría que su código fallara en tiempo de ejecución con un error de enlace. Para evitar este problema, puede configurar la ruta de clase de arranque del compilador para que coincida con el JRE de destino o usar el complemento Animal Sniffer Maven para verificar que su código no use API no deseadas.

Actualización de Java 9
En Java 9, este mecanismo ha cambiado radicalmente al siguiente enfoque:

javac --release N ...

Será semánticamente equivalente a

javac -source N -target N -bootclasspath rtN.jar ...

  • Información sobre las API de versiones anteriores disponibles para javac

    • Almacenado de manera comprimida
    • Solo proporcione API exportadas Java SE N y JDK N que sean neutrales a la plataforma
  • El mismo conjunto de valores de lanzamiento N que para -source / -source
  • Combinaciones incompatibles de opciones rechazadas

Principales ventajas del enfoque --release N :

  • Ningún usuario necesita administrar artefactos que almacenan información API antigua
  • Debe eliminar la necesidad de usar herramientas como el complemento Maven Animal Sniffer
  • Puede usar modismos de compilación más nuevos que javac en versiones anteriores

    • Corrección de errores
    • Mejoras de velocidad

Actualización sobre Java 9 y Maven
Desde la versión 3.6.0 , el maven-compiler-plugin proporciona soporte para Java 9 a través de su opción de release :

El argumento de -release para el compilador de Java, compatible desde Java9

Un ejemplo:

<plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.0</version> <configuration> <release>8</release> </configuration> </plugin>