Mam pewien kod, który używa klas JAXB API, które zostały dostarczone jako część JDK w Javie 6/7/8. Kiedy uruchamiam ten sam kod z Java 9, w czasie wykonywania dostaję błędy wskazujące, że nie można znaleźć klas JAXB.
Klasy JAXB są dostarczane jako część JDK od Java 6, więc dlaczego Java 9 nie może już znaleźć tych klas?
API JAXB są uważane za API Java EE, a zatem nie są już zawarte na domyślnej ścieżce klas w Java SE 9. W Java 11 są one całkowicie usunięte z JDK.
Java 9 wprowadza koncepcje modułów, a domyślnie moduł agregujący java.se
jest dostępny na ścieżce klas (lub raczej ścieżce modułów). Jak sama nazwa wskazuje, moduł zbiorczy java.se
nie zawiera interfejsów API Java EE, które tradycyjnie były dołączane do Javy 6/7/8.
Na szczęście, te API Java EE, które były dostarczane w JDK 6/7/8 są nadal w JDK, ale po prostu nie są domyślnie na ścieżce klas. Dodatkowe interfejsy API Java EE są dostarczane w następujących modułach:
java.activation
java.corba
java.transaction
java.xml.bind << This one contains the JAXB APIs
java.xml.ws
java.xml.ws.annotation
Szybkie i brudne rozwiązanie: (tylko JDK 9/10)
Aby udostępnić interfejsy API JAXB w czasie uruchamiania, należy określić następującą opcję wiersza poleceń:
--add-modules java.xml.bind
.
Ale ja wciąż potrzebuję tego, aby działało to z Javą 8!!!
Jeśli spróbujesz określić --add-modules
ze starszym JDK, wysadzi się, ponieważ jest to'nierozpoznana opcja. Sugeruję jedną z dwóch opcji:
JDK_JAVA_OPTIONS
. Ta zmienna środowiskowa jest [automatycznie odczytywana][1] przez launcher java
dla Javy 9+.-XX:+IgnoreUnrecognizedVMOptions
aby JVM po cichu ignorowała nierozpoznane opcje, zamiast wysadzać się w powietrze. Ale uważaj! Wszelkie inne argumenty linii poleceń, których używasz, nie będą już sprawdzane przez JVM. Opcja ta działa zarówno z Oracle/OpenJDK jak i IBM JDK (od JDK 8sr4)Alternatywne szybkie rozwiązanie: (tylko JDK 9/10)
Zauważ, że możesz uczynić wszystkie powyższe moduły Java EE dostępnymi w czasie uruchamiania poprzez określenie opcji --add-modules java.se.ee
. Moduł java.se.ee
jest modułem zbiorczym, który zawiera java.se.ee
jak również powyższe moduły API Java EE. Uwaga, to nie działa na Javie 11 ponieważ java.se.ee
został usunięty w Javie 11.
Prawidłowe rozwiązanie długoterminowe: (JDK 9 i nowsze)
Moduły API Java EE wymienione powyżej są oznaczone jako @Deprecated(forRemoval=true)
, ponieważ są one [zaplanowane do usunięcia][2] w [Java 11][3]. Tak więc podejście --add-module
nie będzie już działać w Javie 11 po wyjęciu z pudełka.
To, co będziesz musiał zrobić w Javie 11 i dalej, to dołączyć własną kopię API Java EE do ścieżki klasy lub ścieżki modułu. Na przykład, możesz dodać JAX-B APIs jako zależność maven w następujący sposób:
<!-- 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>
Zobacz stronę JAXB Reference Implementation page aby uzyskać więcej szczegółów na temat JAXB.
Aby uzyskać pełne informacje na temat modułowości w Javie, zobacz [JEP 261: System modułów][4].
Dla programisty Gradle lub Android Studio: (JDK 9 i nowsze).
Dodaj następujące zależności do swojego pliku build.gradle:
``groovy dependencies { // Zależności JAX-B dla JDK 9+ implementacja "jakarta.xml.bind:jakarta.xml.bind-api:2.3.2" implementacja "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
To zadziałało w moim przypadku:
<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>
Jak zasugerował @Jasper, aby uniknąć zależności od całej biblioteki EclipseLink, możesz również po prostu zależeć od 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'
Jako zależności dla mojej aplikacji Java 8, która produkuje *.jar, który może być uruchomiony zarówno przez JRE 8 jak i JRE 9 bez dodatkowych argumentów.
Ponadto musi to zostać wykonane gdzieś przed użyciem JAXB API:
System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");
Działa świetnie do tej pory, jako obejście. Nie wygląda to jednak na idealne rozwiązanie...
W czasie kompilacji, jak również w czasie uruchamiania, dodaj przełącznik --add-modules java.xml.bind
.
javac --add-modules java.xml.bind <java file name>
java --add-modules java.xml.bind <class file>
Dobre wprowadzenie do modułów JDK 9
można również znaleźć na stronie :