Ik heb wat code die gebruik maakt van JAXB API klassen die zijn geleverd als onderdeel van de JDK in Java 6/7/8. Wanneer ik dezelfde code uitvoer met Java 9, krijg ik tijdens runtime fouten die aangeven dat JAXB klassen niet gevonden kunnen worden.
De JAXB klassen zijn beschikbaar als onderdeel van de JDK sinds Java 6, dus waarom kan Java 9 deze klassen niet meer vinden?
De JAXB API's worden beschouwd als Java EE API's, en zijn daarom niet langer opgenomen in het standaard klassepad in Java SE 9. In Java 11 zijn ze volledig verwijderd uit de JDK.
Java 9 introduceert de concepten van modules, en standaard is de java.se
aggregate module beschikbaar op het class path (of beter gezegd, module path). Zoals de naam al aangeeft, bevat de java.se
aggregate module niet de Java EE APIs die traditioneel gebundeld zijn met Java 6/7/8.
Gelukkig zitten deze Java EE APIs die in JDK 6/7/8 werden meegeleverd nog steeds in de JDK, maar ze staan alleen'niet standaard op het class pad. De extra Java EE API's worden geleverd in de volgende modules:
java.activation
java.corba
java.transaction
java.xml.bind << This one contains the JAXB APIs
java.xml.ws
java.xml.ws.annotation
Snelle en vieze oplossing: (Alleen JDK 9/10)
Om de JAXB APIs beschikbaar te maken tijdens runtime, specificeer de volgende command-line optie:
--add-modules java.xml.bind
Maar ik heb dit nog steeds nodig om te werken met Java 8!!!
Als je --add-modules
probeert te specificeren met een oudere JDK, zal het opgeblazen worden omdat het een niet-herkende optie is. Ik stel een van de twee opties voor:
JDK_JAVA_OPTIONS
omgevingsvariabele. Deze omgevingsvariabele wordt automatisch gelezen door de java
launcher voor Java 9+.-XX:+IgnoreUnrecognizedVMOptions
toevoegen om de JVM stilletjes niet-herkende opties te laten negeren, in plaats van op te blazen. Maar pas op! Alle andere commandoregel args die je gebruikt zullen niet langer voor je gevalideerd worden door de JVM. Deze optie werkt zowel met Oracle/OpenJDK als met IBM JDK (vanaf JDK 8sr4)Alternatieve snelle oplossing: (alleen JDK 9/10)
Merk op dat je alle bovenstaande Java EE modules beschikbaar kunt maken tijdens runtime door de --add-modules java.se.ee
optie te specificeren. De java.se.ee
module is een geaggregeerde module die zowel java.se.ee
als de bovenstaande Java EE API modules bevat. Let op, dit werkt niet op Java 11 omdat java.se.ee
is verwijderd in Java 11.
Juiste lange termijn oplossing: (JDK 9 en verder)
De Java EE API modules hierboven zijn allemaal gemarkeerd met @Deprecated(forRemoval=true)
, omdat ze scheduled for removal zijn in Java 11. Dus de --add-module
aanpak zal niet meer werken in Java 11 out of the box.
Wat je moet doen in Java 11 en verder is je eigen kopie van de Java EE API's opnemen in het class path of module path. Bijvoorbeeld, je kunt de JAX-B API's toevoegen als een maven afhankelijkheid zoals dit:
<!-- 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>
Zie de JAXB Referentie Implementatie pagina voor meer details over JAXB.
Voor volledige details over Java modulariteit, zie JEP 261: Module System
Voor Gradle of Android Studio ontwikkelaar: (JDK 9 en verder)
Voeg de volgende afhankelijkheden toe aan uw build.gradle bestand:
afhankelijkheden {
// JAX-B afhankelijkheden voor JDK 9+
implementatie "jakarta.xml.bind:jakarta.xml.bind-api:2.3.2"
implementatie "org.glassfish.jaxb:jaxb-runtime:2.3.2"
}
Dit werkte voor mij:
<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>
Zoals @Jasper voorstelde, om niet afhankelijk te zijn van de hele EclipseLink bibliotheek, kun je ook alleen afhankelijk zijn van 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'
Als afhankelijkheden voor mijn Java 8 app, die een *.jar produceert die zowel door JRE 8 als JRE 9 kan worden uitgevoerd zonder extra argumenten.
Bovendien moet dit ergens worden uitgevoerd voordat JAXB API zal worden gebruikt:
System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");
Werkt geweldig tot nu toe, als een workaround. Ziet er echter niet uit als een perfecte oplossing...
Voeg zowel tijdens het compileren als tijdens het uitvoeren de switch --add-modules java.xml.bind
toe
javac --add-modules java.xml.bind <java file name>
java --add-modules java.xml.bind <class file>
Een goede introductie van de JDK 9
modules kan ook worden gevonden op :