Configuración de Maven Java Version ignorada por Eclipse / Idea

Yo tengo:

    org.apache.maven.plugins maven-compiler-plugin 3.1  1.6 1.6      

Sin embargo, no tengo ningún problema para declarar:

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

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

Estás golpeando el malentendido de la comstackción cruzada de target opciones de source / target . Usando una versión principal en su classpath (JDK 7 u 8) pero que desea comstackr contra una versión menor (6 en su caso).
La comstackción estará bien, pero tendrá errores en el tiempo de ejecución (es decir, NoClassDefFoundError o NoSuchMethodError , probablemente también el LinkageError más genérico).

Usando el source / target , el comstackdor de Java se puede usar como un comstackdor 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 comstackdor sería suficiente. Sin embargo, la opción de source especifica contra qué versión estamos comstackndo, mientras que la opción de target especifica la versión de Java más baja que admite.

El comstackdor trabaja en la generación de códigos de bytes y la source y el target se utilizan para generar códigos de bytes compatibles durante la comstackción cruzada. Sin embargo, el comstackdor no maneja la API de Java (se proporcionan como parte de la instalación de JDK, el famoso archivo rt.jar ). El comstackdor no tiene ningún conocimiento de API, simplemente comstack contra el rt.jar actual. Por lo tanto, al comstackr con target=1.6 utilizando JDK 1.7, el comstackdor apuntará al JDK 7 rt.jar .

Entonces, ¿cómo podemos tener una comstackció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 a rt.jar de la versión de Java objective deseada (por lo tanto, debe tener el JDK de destino instalado en su máquina). Como tal, javac comstackrá efectivamente contra la buena API de Java.

¡Pero eso aún puede no ser suficiente!

No todas las API de Java provienen de rt.jar . Otras clases son proporcionadas por la carpeta lib\ext . Una opción adicional de javac se usa para eso, extdirs . De los documentos oficiales de Oracle

Si está comstackndo de forma cruzada (comstackndo clases con 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 utilizando las opciones source / target y bootclasspath , aún podemos perder algo durante la comstackción cruzada, como también se explica en el ejemplo oficial que viene con la documentación de javac.

Java Platform JDK’s javac también comstackría de forma predeterminada contra sus propias clases de arranque, por lo que necesitamos decirle a javac que compile contra las clases de arranque JDK 1.5. Hacemos esto con -bootclasspath y -extdirs. No hacerlo podría permitir la comstackción contra una API de plataforma Java que no estaría presente en una máquina virtual de 1.5 y fallaría en el tiempo de ejecución.

Pero … ¡puede que aún no sea suficiente!

De la documentación oficial de Oracle

Incluso cuando bootclasspath y -source / -target están todos configurados adecuadamente para la comstackción cruzada, los contratos internos del comstackdor, como la comstackción de 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 (a partir de la documentación oficial de Oracle )

La manera más fiable de producir archivos de clase que funcionarán en un JDK particular y posterior es comstackr los archivos fuente utilizando el JDK más antiguo de interés. A excepción de eso, el bootclasspath debe establecerse para una sólida comstackción cruzada con 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 de Java 7 y Java 8 y API. ¿Cómo puede entonces ser compatible con Java 7 y 8?

Spring hace uso de la flexibilidad source / target y bootclasspath . Spring 4 siempre comstack con el source / target en Java 6, de modo que bytecode aún puede ejecutarse bajo JRE 6. Por lo tanto, no se utilizan las características del lenguaje Java 7/8: la syntax 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, Stream y muchas otras API de Java 8. A continuación, inyecta beans en función de Java 7 o Java 8 API solo cuando se detecta JRE 7/8 en tiempo de ejecución: ¡enfoque inteligente!

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

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

Puede agregar lo siguiente a su archivo POM:

    org.codehaus.mojo animal-sniffer-maven-plugin 1.14   org.codehaus.mojo.signature java16 1.0     ensure-java-1.6-class-library verify  check       

Y la comstackción fallará tan pronto como utilice la API JDK 7 mientras desea utilizar solo la API JDK 6.

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

Nota : el mero hecho de establecer la opción de target no garantiza que su código realmente se ejecute en un JRE con la versión especificada. El inconveniente es el uso involuntario de las API que solo existen en JRE posteriores que harían que tu código fallara en tiempo de ejecución con un error de enlace. Para evitar este problema, puede configurar la ruta de clases de arranque del comstackdor para que coincida con el JRE objective o usar el complemento Animal Sniffer Maven para verificar que su código no use API no intencionadas.


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 forma comprimida
    • Solo proporcione APIs compatibles con Java SE N y JDK N que sean plataforma neutral
  • Mismo conjunto de valores de liberación 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 antigua de API
  • Debe eliminar la necesidad de utilizar herramientas como el plugin Maven Animal Sniffer
  • Puede usar modismos de comstackción más nuevos que el 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 , maven-compiler-plugin brinda soporte para Java 9 a través de su opción de release :

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

Un ejemplo:

  maven-compiler-plugin 3.6.0  8