Tengo un código que utiliza clases de la API JAXB que se han proporcionado como parte del JDK en Java 6/7/8. Cuando ejecuto el mismo código con Java 9, en tiempo de ejecución obtengo errores que indican que no se pueden encontrar las clases JAXB.
Las clases JAXB se han proporcionado como parte del JDK desde Java 6, así que ¿por qué Java 9 ya no puede encontrar estas clases?
Las APIs JAXB se consideran APIs de Java EE, y por lo tanto ya no están contenidas en la ruta de clases por defecto en Java SE 9. En Java 11 se eliminan completamente del JDK.
Java 9 introduce los conceptos de módulos, y por defecto el módulo agregado java.se
está disponible en la ruta de clases (o más bien, de módulos). Como su nombre indica, el módulo agregado java.se
no incluye las API de Java EE que tradicionalmente se han incluido en Java 6/7/8.
Afortunadamente, estas API de Java EE que se proporcionaban en el JDK 6/7/8 siguen estando en el JDK, pero simplemente no están en la ruta de la clase por defecto. Las API Java EE adicionales se proporcionan en los siguientes módulos:
java.activation
java.corba
java.transaction
java.xml.bind << This one contains the JAXB APIs
java.xml.ws
java.xml.ws.annotation
Solución rápida y sucia: (sólo JDK 9/10)
Para que las APIs JAXB estén disponibles en tiempo de ejecución, especifique la siguiente opción de línea de comandos:
--add-modules java.xml.bind
¡Pero aún necesito que esto funcione con Java 8!!!
Si intentas especificar --add-modules
con un JDK más antiguo, explotará porque es una opción no reconocida. Sugiero una de las dos opciones:
JDK_JAVA_OPTIONS
. Esta variable de entorno es [leída automáticamente][1] por el lanzador java
para Java 9+.-XX:+IgnoreUnrecognizedVMOptions
para hacer que la JVM ignore silenciosamente las opciones no reconocidas, en lugar de explotar. Pero ¡cuidado! Cualquier otro argumento de la línea de comandos que utilices ya no será validado por la JVM. Esta opción funciona tanto con Oracle/OpenJDK como con IBM JDK (a partir de JDK 8sr4)Solución rápida alternativa: (sólo JDK 9/10)
Tenga en cuenta que puede hacer que todos los módulos Java EE anteriores estén disponibles en tiempo de ejecución especificando la opción --add-modules java.se.ee
. El módulo java.se.ee
es un módulo agregado que incluye java.se.ee
así como los módulos de la API Java EE anteriores. Tenga en cuenta que esto no funciona en Java 11 porque java.se.ee
fue eliminado en Java 11.
Solución adecuada a largo plazo: (JDK 9 y posteriores)
Los módulos de la API de Java EE listados arriba están marcados como @Deprecated(forRemoval=true)
, porque están [programados para ser eliminados][2] en [Java 11][3]. Por lo tanto, el enfoque de --add-module
ya no funcionará en Java 11 fuera de la caja.
Lo que tendrá que hacer en Java 11 y en adelante es incluir su propia copia de las API de Java EE en la ruta de la clase o la ruta del módulo. Por ejemplo, puede añadir las APIs JAX-B como una dependencia de maven de la siguiente manera:
<!-- API, java.xml.bind module -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>
<!-- Runtime, com.sun.xml.bind module -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>
Consulte la página de implementación de referencia de JAXB para obtener más detalles sobre JAXB.
Para obtener todos los detalles sobre la modularidad de Java, consulte [JEP 261: Sistema de módulos][4].
Para desarrolladores de Gradle o Android Studio: (JDK 9 y posteriores)
Añade las siguientes dependencias a tu archivo build.gradle:
``groovy dependencias { // Dependencias de JAX-B para JDK 9+ implementación "jakarta.xml.bind:jakarta.xml.bind-api:2.3.2" implementación "org.glassfish.jaxb:jaxb-runtime:2.3.2" }
[1]: https://www.oracle.com/technetwork/java/javase/9-new-features-3745613.html#JDK-8170832
[2]: http://openjdk.java.net/jeps/320
[3]: http://openjdk.java.net/projects/jdk/11/
[4]: http://openjdk.java.net/jeps/261
[5]: https://stackoverflow.com/a/46455026/3763032
Esto me ha funcionado:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.7.0</version>
</dependency>
Como sugirió @Jasper, para evitar depender de toda la biblioteca EclipseLink, también puedes depender sólo de EclipseLink MOXy:
Maven
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.7.3</version>
</dependency>
Gradle
compile group: 'org.eclipse.persistence', name: 'org.eclipse.persistence.moxy', version: '2.7.3'
Como dependencias para mi aplicación Java 8, que produce un *.jar que puede ser ejecutado tanto por JRE 8 como por JRE 9 sin argumentos adicionales.
Además, esto necesita ser ejecutado en algún lugar antes de que la API JAXB sea utilizada:
System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");
Funciona muy bien hasta ahora, como una solución. Aunque no parece una solución perfecta...
En el momento de la compilación, así como en tiempo de ejecución, añadir el interruptor --add-modules java.xml.bind
.
javac --add-modules java.xml.bind <java file name>
java --add-modules java.xml.bind <class file>
Una buena introducción de los módulos del JDK 9
también se puede encontrar en