1193 votes

Comment résoudre l'erreur java.lang.NoClassDefFoundError : javax/xml/bind/JAXBException

J'ai un code qui utilise les classes de l'API JAXB qui ont été fournies en tant que partie du JDK dans Java 6/7/8. Lorsque j'exécute le même code avec Java 9, j'obtiens, au moment de l'exécution, des erreurs indiquant que les classes JAXB sont introuvables.

Les classes JAXB sont fournies dans le JDK depuis Java 6, alors pourquoi Java 9 ne trouve-t-il plus ces classes ?

2 votes

La partie supplémentaire dans cette réponse concerne la migration de ces API.

9 votes

Si vous construisez avec Java 8, votre code sera compilé, mais si vous essayez d'exécuter ce code compilé sur Java 9+, il échouera car JAX-B n'est pas présent.

2 votes

Pour Java 11, la solution de cet article est à jour : crunchify.com/java-11-et-javax-xml-bind-jaxbcontext

1723voto

Andy Guibert Points 14403

Les API JAXB sont considérées comme des API Java EE et ne figurent donc plus dans le classpath par défaut dans Java SE 9. Dans Java 11, elles sont complètement supprimées du JDK.

Java 9 introduit les concepts de modules et, par défaut, la fonction java.se Le module d'agrégation est disponible dans le classpath (ou plutôt le module-path). Comme son nom l'indique, le module java.se Le module d'agrégation fait no incluent les API Java EE qui ont été traditionnellement regroupées avec Java 6/7/8.

Heureusement, ces API Java EE qui étaient fournies dans le JDK 6/7/8 sont toujours dans le JDK, mais elles ne sont pas sur le classpath par défaut. Les API Java EE supplémentaires sont fournies dans les modules suivants :

java.activation
java.corba
java.transaction
java.xml.bind  << This one contains the JAXB APIs
java.xml.ws
java.xml.ws.annotation

Solution rapide et sale : (JDK 9/10 seulement)

Pour rendre les API JAXB disponibles au moment de l'exécution, spécifiez l'option de ligne de commande suivante :

--add-modules java.xml.bind

Mais j'ai encore besoin que cela fonctionne avec Java 8 ! !!

Si vous essayez de spécifier --add-modules avec un JDK plus ancien, il va exploser parce que c'est une option non reconnue. Je suggère l'une des deux options suivantes :

  1. Vous pouvez définir n'importe quelle option réservée à Java 9+ en utilisant l'option JDK_JAVA_OPTIONS variable d'environnement. Cette variable d'environnement est lu automatiquement par le java pour Java 9+.
  2. Vous pouvez ajouter le -XX:+IgnoreUnrecognizedVMOptions pour que la JVM ignore silencieusement les options non reconnues, au lieu d'exploser. Mais attention ! Tout autre argument de ligne de commande que vous utilisez ne sera plus validé pour vous par la JVM. Cette option fonctionne avec Oracle/OpenJDK ainsi qu'avec IBM JDK (à partir de JDK 8sr4).

Autre solution rapide : (JDK 9/10 uniquement)

Notez que vous pouvez rendre tous les modules Java EE susmentionnés disponibles au moment de l'exécution en spécifiant l'attribut --add-modules java.se.ee option. Le site java.se.ee est un module agrégé qui comprend java.se.ee ainsi que les modules API Java EE ci-dessus. Remarque, cette ne fonctionne pas sur Java 11 parce que java.se.ee a été supprimé dans Java 11.


Solution appropriée à long terme : (JDK 9 et au-delà)

Les modules API Java EE énumérés ci-dessus sont tous marqués @Deprecated(forRemoval=true) parce qu'ils sont prévue pour le déménagement sur Java 11 . Ainsi, le --add-module ne fonctionnera plus dans Java 11 prêt à l'emploi.

À partir de Java 11, vous devrez inclure votre propre copie des API Java EE dans le classpath ou le chemin des modules. Par exemple, vous pouvez ajouter les API JAX-B en tant que dépendance Maven comme ceci :

<!-- 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>

Voir le Page de mise en œuvre de la référence JAXB pour plus de détails sur JAXB.

Pour plus de détails sur la modularité de Java, voir JEP 261 : Système de modules

Pour les développeurs Gradle ou Android Studio : (JDK 9 et au-delà)

Ajoutez les dépendances suivantes à votre build.gradle fichier :

dependencies {
    // JAX-B dependencies for JDK 9+
    implementation "jakarta.xml.bind:jakarta.xml.bind-api:2.3.2"
    implementation "org.glassfish.jaxb:jaxb-runtime:2.3.2"
}

0 votes

Il suffit donc de l'ajouter aux dépendances de votre gradle ?

9 votes

Donc, si les modules de l'API Java EE sont marqués comme étant dépréciés, cela signifie-t-il qu'il est possible que JAXB ne soit plus disponible au moment de l'exécution dans Java 10 ? Cela ressemble à un retour en arrière. Nous devrons revenir à la pratique pré-6 d'inclure JAXB comme une dépendance.

0 votes

Je ne suis pas sûr de la version dans laquelle il sera supprimé, mais selon la javadoc de Java 9, le module est marqué @Deprecated(forRemoval=true) donc il est sûr de dire qu'il sera supprimé à terme. Voir ici : download.java.net/java/jdk9/docs/api/java.xml.bind-summary.html

385voto

jdev Points 2382

Dans mon cas (spring boot fat jar), j'ajoute simplement ce qui suit à pom.xml.

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>

14 votes

1 votes

Puis-je ajouter ceci avec <scope>runtime</scope> ?

10 votes

Ajouter la dépendance de gradle comme ceci testCompile('javax.xml.bind:jaxb-api') a fonctionné pour moi.

87voto

Andremoniy Points 7349

Aucune de ces solutions n'a fonctionné pour moi dans le récent JDK 9.0.1.

J'ai trouvé que cette liste de dépendances est suffisante pour un bon fonctionnement, alors vous n'ont pas besoin pour spécifier explicitement --add-module (bien qu'il soit spécifié dans les pom's de ces dépendances). La seule chose dont vous avez besoin est de spécifier cette liste de dépendances :

<dependencies>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
</dependencies>

2 votes

Pour le JDK 8, enlevez le jaxb-core et le jaxb-impl de ci-dessus.

0 votes

Où puis-je trouver le fichier correspondant ?

0 votes

Quel fichier @Anil ?

48voto

Mikhail Kholodkov Points 3238

Cela a marché pour moi :

<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>

Mise à jour

Comme @Jasper l'a suggéré, afin d'éviter de dépendre de toute la bibliothèque EclipseLink, vous pouvez également dépendre uniquement d'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'

Comme dépendances pour mon application Java 8, qui produit un *.jar qui peut être exécuté par JRE 8 ou JRE 9 sans arguments supplémentaires.

En outre, il doit être exécuté quelque part avant que l'API JAXB ne soit utilisée :

System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");

Cela fonctionne très bien jusqu'à présent, comme solution de rechange. Mais ça ne semble pas être une solution parfaite...

6 votes

En ajoutant org.eclipse.persistence:eclipselink juste pour obtenir les API JAXB est une dépendance très lourde, à moins que vous n'utilisiez déjà eclipselink ?

4 votes

Oui il est lourd (~9mb) et oui je l'ai déjà utilisé. J'ai mentionné qu'il s'agit simplement d'une solution de rechange pour ceux qui, peut-être temporairement, devront utiliser les JRE 8 et 9 pour le même jar/war sans fournir d'arguments en ligne de commande.

2 votes

Pour des raisons d'interopérabilité entre les JDK 8 et 9, je recommanderais d'utiliser la version -XX:+IgnoreUnrecognizedVMOptions option de ligne de commande (j'ai mis à jour ma réponse avec des détails)

39voto

Cesar Rodriguez T Points 373

C'est parce que la version de java si vous utilisez jdk 9 ou une version plus récente ajoutez simplement ceci à votre pom

<dependency>
  <groupId>javax.xml.bind</groupId>
  <artifactId>jaxb-api</artifactId>
  <version>2.3.0</version>
</dependency>

2 votes

Je rencontre ce problème tout le temps avec les guides de Spring Boot... Merci beaucoup.

2 votes

@Cesar Rodriguez T, j'ai essayé ceci avec un exemple swagger et la compilation a fonctionné mais l'exécution a donné des erreurs. J'ai utilisé la réponse choisie qui incluait plus de dépendances et cela a fonctionné.

0 votes

Dans le fichier pom.xml de votre projet

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X