Ich habe einen Code, der JAXB-API-Klassen verwendet, die als Teil des JDK in Java 6/7/8 bereitgestellt wurden. Wenn ich denselben Code mit Java 9 ausführe, erhalte ich zur Laufzeit die Fehlermeldung, dass JAXB-Klassen nicht gefunden werden können.
Die JAXB-Klassen werden seit Java 6 als Teil des JDK bereitgestellt. Warum kann Java 9 diese Klassen also nicht mehr finden?
Die JAXB-APIs werden als Java EE-APIs betrachtet und sind daher in Java SE 9 nicht mehr im Standardklassenpfad enthalten. In Java 11 werden sie vollständig aus dem JDK entfernt.
Java 9 führt das Konzept der Module ein, und standardmäßig ist das Aggregatmodul java.se
im Klassenpfad (oder besser gesagt im Modulpfad) verfügbar. Wie der Name schon sagt, enthält das Aggregatmodul "java.se" nicht die Java EE-APIs, die traditionell mit Java 6/7/8 gebündelt wurden.
Glücklicherweise sind diese Java EE-APIs, die in JDK 6/7/8 enthalten waren, immer noch im JDK enthalten, aber sie sind nur nicht standardmäßig im Klassenpfad. Die zusätzlichen Java EE-APIs werden in den folgenden Modulen bereitgestellt:
java.activation
java.corba
java.transaction
java.xml.bind << This one contains the JAXB APIs
java.xml.ws
java.xml.ws.annotation
Schnelle und schmutzige Lösung: (nur JDK 9/10)
Um die JAXB-APIs zur Laufzeit verfügbar zu machen, geben Sie die folgende Befehlszeilenoption an:
--add-modules java.xml.bind
Aber das muss noch mit Java 8 funktionieren!!!
Wenn Sie versuchen, --add-modules
mit einem älteren JDK anzugeben, wird es scheitern, weil es eine nicht erkannte Option ist. Ich schlage eine von zwei Optionen vor:
JDK_JAVA_OPTIONS
setzen. Diese Umgebungsvariable wird vom java
Launcher für Java 9+ automatisch gelesen.-XX:+IgnoreUnrecognizedVMOptions
hinzufügen, um die JVM dazu zu bringen, nicht erkannte Optionen stillschweigend zu ignorieren, anstatt zu explodieren. Aber Vorsicht! Alle anderen Befehlszeilen-Args, die Sie verwenden, werden von der JVM nicht mehr für Sie validiert. Diese Option funktioniert sowohl mit Oracle/OpenJDK als auch mit IBM JDK (ab JDK 8sr4)Alternative schnelle Lösung: (nur JDK 9/10)
Beachten Sie, dass Sie alle oben genannten Java EE-Module zur Laufzeit verfügbar machen können, indem Sie die Option --add-modules java.se.ee
angeben. Das Modul "java.se.ee" ist ein aggregiertes Modul, das sowohl "java.se.ee" als auch die oben genannten Java EE API-Module enthält. Beachten Sie, dass dies nicht mit Java 11 funktioniert, da java.se.ee
in Java 11 entfernt wurde.
Langfristig richtige Lösung: (JDK 9 und höher)
Die oben aufgeführten Java EE-API-Module sind alle mit @Deprecated(forRemoval=true)
gekennzeichnet, weil sie in Java 11 zur Entfernung vorgesehen sind. Der Ansatz --add-module
wird also in Java 11 nicht mehr ohne weiteres funktionieren.
Ab Java 11 müssen Sie Ihre eigene Kopie der Java EE APIs in den Klassen- oder Modulpfad aufnehmen. Zum Beispiel können Sie die JAX-B APIs wie folgt als Maven-Abhängigkeit hinzufügen:
<!-- 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>
Weitere Details zu JAXB finden Sie auf der JAXB Reference Implementation page.
Ausführliche Informationen über die Modularität von Java finden Sie in JEP 261: Module System
Für Gradle oder Android Studio Entwickler: (JDK 9 und höher)
Fügen Sie die folgenden Abhängigkeiten zu Ihrer build.gradle-Datei hinzu:
Abhängigkeiten {
// JAX-B-Abhängigkeiten für JDK 9+
Implementierung "jakarta.xml.bind:jakarta.xml.bind-api:2.3.2"
Implementierung "org.glassfish.jaxb:jaxb-runtime:2.3.2"
}
Das hat bei mir funktioniert:
<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>
Wie @Jasper vorschlug, kann man, um nicht von der gesamten EclipseLink-Bibliothek abhängig zu sein, auch nur von EclipseLink MOXy abhängig sein:
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'
Als Abhängigkeiten für meine Java 8-Anwendung, die ein *.jar erzeugt, das sowohl von JRE 8 als auch von JRE 9 ohne zusätzliche Argumente ausgeführt werden kann.
Darüber hinaus muss es irgendwo ausgeführt werden, bevor die JAXB-API verwendet wird:
System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");
Funktioniert bis jetzt gut, als Workaround. Sieht aber nicht wie eine perfekte Lösung aus...
Fügen Sie zum Zeitpunkt der Kompilierung und zur Laufzeit den Schalter --add-modules java.xml.bind
hinzu.
javac --add-modules java.xml.bind <java file name>
java --add-modules java.xml.bind <class file>
Eine gute Einfuehrung in die Module des JDK 9
findet sich auch unter :