JAXB und SOAP in JAVA 11

Montag, 19.11.2018

JAXB und SOAP in JAVA 11

Mit Java 11 wurde es ernst: Die mit Java 9 als deprecated markierten Module sind in Java 11 mit JEP320 nun entfallen. Dazu gehören unter anderem auch die beliebten Module javax.xml.bind (JAXB) und javax.xml.ws (JAX-WS). Versucht man nun also, unter einem aktuellen Java 11 die Module JAXB oder JAX-WS zu verwenden, führt dies erst einmal zu einem Fehler. Auch im Hinblick auf die Build-Zeit ergibt sich in Java 11 ein Problem: Die bisher mit dem JDK verfügbaren Tools xjc, schemagen, wsgen und wsimport sind entfallen.

Zwar sind im JEP320 entsprechende Maven-Artefakte genannt, welche für die entfallenen Module eine Referenzimplementierung bereithalten, jedoch werden diese insbesondere von älteren Frameworks nicht als Dependency referenziert. Im Fall von Spring Boot werden die notwendigen Bibliotheken mit der aktuellen Version 2.1 mit Java 11-Support eingebunden.

Reicht das aus? Es ist an der Zeit, sich die verfügbaren Dependencies mal etwas genauer anzuschauen:

JAXB

Im Fall von JAXB wird im JEP320 als Maven-Artefakt com.sun.xml.bind:jaxb-ri als Referenz-Implementierung genannt. Leider handelt es sich dabei um ein ZIP-Archiv. Schaut man sich das Archiv genauer an, enthält es entsprechende JARs sowie weitere Dokumentation und auch die ebenfalls im JDK entfallenen Tools xjc und schemagen. Als direkte Dependency im nächsten Java 11-Projekt ist das aber nicht wirklich brauchbar.

Helfen kann die oben genannte Dokumentation zur Referenz-Implementierung: Hier werden javax.xml.bind:jaxb-api als API und org.glassfish.jaxb:jaxb-runtime als Implementierung gelistet.

Bei einer Suche im Maven-Central nach Artefakten der Group-Id com.sun.xml.bind wird man mit com.sun.xml.bind:jaxb-impl und com.sun.xml.bind:jaxb-core ebenso fündig. Das Dependency-Paar wird zum Beispiel auch vom JAXB-Support in Apache Camel (Version 2.22.1) referenziert. Es handelt sich dabei jedoch um eine alte JAXB Runtime-Implementierung, was auch die Dokumentation der entsprechenden POMs besagt.

Ein Blick in die Starter-Konfiguration des neuen Spring Boot 2.1, zum Beispiel den spring-boot-starter-data-jpa, zeigt das dort zwar die JAXB API javax.xml.bind:jaxb-api referenziert wird, nicht jedoch eine Implementierung. Ein Test bestätigt, dass die entsprechende Runtime-Dependency zusätzlich eingefügt werden muss. Hier besteht durchaus die Auswahl zwischen der Glassfish-Dependency und dem Pärchen der alten Implementierung – beides funktioniert bei einem Test unter Java 11. Das ist vor dem Hintergrund, dass zum Beispiel Apache Camel in der oben genannten Erweiterung die alte Implementierung nutzt, ganz sinnvoll. Andernfalls würden sich zwei unterschiedliche Implementierungen gleichzeitig im Projekt finden.

JAX-WS (Hier SOAP)

Für JAX-WS, bzw. in diesem Beispiel konkret SOAP im Kontext einer Spring Boot-Anwendung, wird im JEP320 als Maven-Artefakt com.sun.xml.ws:jaxws-ri genannt. Auch hier handelt es sich wieder um ein ZIP-Archiv aus JAR-Files sowie Dokumentation und den ebenfalls entfallenen Tools wsgen und wsimport.

Als JAR ist im Maven-Central mit com.sun.xml.ws:jaxws-rt direkt ein Artefakt für die Verwendung in Maven verfügbar um ein Spring Boot-Projekt zu erweitern. Diese besitzt jedoch eine ganze Reihe transitiver Abhängigkeiten. Darunter auch die JAXB-Implementierung der Glassfish-Group-Id von oben. Werden im Rahmen eines einfachen Spring Boot-Projektes lediglich SOAP-Services verwendet, so reicht in einem ersten Test für Spring Boot 2.0 neben einer der JAXB-Implementierungen des vorherigen Abschnittes, die Dependency auf die JAAS-Implementierung aus. Diese ist unter com.sun.xml.messaging.saaj:saaj-impl zu finden.

Im Fall von Spring Boot 2.1 wurde die genannte SAAJ-Implementierung direkt dem Starter spring-boot-starter-web-services zusammen mit der JAXWS-API hinzugefügt, so dass die zusätzliche Dependency im Projekt transitiv vorhanden ist und damit als direkte Dependency entfällt. Eine JAXB-Implementierung wird jedoch weiterhin benötigt.

Generierung von JAXB-annotierten Klassen

Sich zur Entwicklungszeit aus z.B. einer gegebenen XSD die JAXB annotierten Klassen generieren zu lassen, ist nach dem Entfallen der Tools und damit insbesondere des Tools xjc problematisch.

Im eingangs genannten ZIP-Archiv der JAXB-Implementierung ist das xjc-Tool zwar enthalten, das setzt in der Entwicklung dann aber natürlich voraus, dass dieses entsprechend installiert bzw. vorgehalten werden muss. Es wäre zwar möglich, die Dependency z.B. mit Maven zu beziehen, zu entpacken und dann zu verwenden – elegant und wartbar ist das aber erstmal auch nicht.

Das Maven-Plugin jaxb2-maven-plugin funktioniert aktuell leider noch nicht mit Java 11. Dazu gibt es noch einen Issue auf Github. Ähnlich sieht es mit dem Maven-Plugin von Apache CXF (org.apache.cxf:cxf-codegen-plugin) aus: Das soll mit Version 3.3.0 unter Java 11 zwar funktionieren, leider ist die Version jedoch noch nicht veröffentlicht.

In der Zwischenzeit gibt es aber dennoch keinen Grund zum Verzweifeln: Die alte Implementierung des xjc-Tools steht in der Maven-Central unter com.sun.xml.bind:jaxb-xjc auch als JAR-Artefakt zur Verfügung. Erste Tests zeigen jedoch, dass das Maven-Artefakt offenbar nicht ohne weitere Dependencies funktioniert – es benötigt unter anderem eine JAXB-Implementierung. Davon gibt es, wie wir gesehen haben, eine entsprechende Auswahl. Alternativ steht aber im Kontext des Glassfish auch hier die aktuelle Implementierung zur Verfügung. Mit org.glassfish.jaxb:jaxb-xjc gibt es eine JAR-Version, welche alle benötigten Dependencies transitiv referenziert. Damit lässt sich das xjc-Tooling recht einfach weiter in Maven verwenden.

Die dabei aufkeimende Euphorie wird beim ersten Anlauf jedoch gleich wieder etwas gedämpft: Versucht man nämlich, das Tool via exec-maven-plugin zu starten, zeigt sich ein kleiner Schönheitsfehler: Das XJC-Tool scheint seine Arbeit auch im Erfolgsfall mit einem System.exit(0) zu beenden. Damit ist dann auch der Maven-Prozess erstmal beendet und der Build läuft nicht weiter. Als Ausführung im Maven-Build zur Generierung von Sourcen vor dem eigentlichen Compile ist das eher unschön.

Leider unterstützt das Plugin für eine Java-Ausführung keine Fork-Prozesse, um die Ausführung in einer gesonderten JVM-Instanz zu starten. Dies kann zwar manuell über das Goal exec erfolgen, indem der Java-Prozess via java.exe direkt gestartet wird, leider fällt dann ein zweites Problem auf: Das Ausgabe-Verzeichnis der zu erzeugenden Java-Sourcen wird bei der Ausführung nicht automatisch angelegt. Fehlt es, bricht das Tool ab. Das ist im Maven-Kontext eher unschön, da nach einem mvn clean das Ausgabe-Verzeichnis gelöscht wird. Die Sourcen davon auszunehmen würde den Convention-Gedanken des Maven-Ansatzes verletzen.

Da es für das Anlegen des Ausgabe-Verzeichnisses ohnehin auf ein maven-antrun-plugin hinausläuft, lässt sich der Java-Aufruf auch direkt damit erledigen:

Da die Dependency auf das Tool nur zur Build-Zeit und nur für diese eine Plugin-Ausführung benötigt wird, wurde die Dependency direkt für das Plugin definiert. Damit kann sich die Tool-Ausführung dann auch auf den Plugin-Classpath beschränken.

Im Gegensatz zum exec-maven-plugin gibt es bei dem maven-antrun-plugin keine Option, den Pfad der erzeugten Source-Files (target/generated-sources/ws in unserem Beispiel) zum Source-Path für den späteren Compile hinzuzufügen.

Dazu muss das build-helper-maven-plugin verwendet werden:

Fazit

Für die mit Java 11 entfallenen Module gibt es teils mehrere Alternativen, welche direkt über die Maven-Central bezogen werden können. Spring Boot 2.1 hat die entsprechenden API-Dependencies mit aufgenommen, die eigentlichen Implementierungen müssen jedoch weiterhin als Abhängigkeit manuell hinzugenommen werden.

Andere Bibliotheken wie Apache Camel referenzieren in der aktuellen Version weiterhin die alten Implementierungs-Artefakte. Es bleibt also abzuwarten, wie viele Implementierungen sich mit der Zeit ergeben werden und wie viele dieser Implementierungen sich später als transitive Abhängigkeiten in einem realen Projekt gleichzeitig wiederfinden werden.

Update 03.2019

Zum leichteren Kopieren wurden die Bilder der Code-Listings ersetzt. Darüber hinaus ist das hier gezeigte Beispiel zum Aufruf des XJC via maven-antrun-plugin auch auf GitHub verfügbar.

Das oben genannte jaxb2-maven-plugin ist aktuell noch nicht für Java 11 verfügbar. Es gibt jedoch bereits eine alternative Implementierung für Java 8 bis 11, welche unter com.github.davidmoten:jax-maven-plugin auch im Maven-Central verfügbar ist. Erste Tests mit dem oben genannten Beispiel waren erfolgreich.

Update 05.2019

Das Code-Beispiel zur Ausführung des XJC via maven-antrun-plugin wurde um die aktuelle Maven-Dependency von Apache ANT ergänzt. Wie auch in den Kommentaren erwähnt, kann diese bei der Ausführung unter Java 11 notwendig werden.

UPDATE 04.2021 - Java hat sich weiterentwickelt

Java hat sich weiterentwickelt. Mit Java 17 steht das nächste LTS-Release nach Java 11 vor der Tür. Was das bedeutet und wie es mit Java weitergeht behandeln wir in unserem neuen Blogbeitrag.


zurück zur Blogübersicht

Diese Beiträge könnten Sie ebenfalls interessieren

Keinen Beitrag verpassen – viadee Blog abonnieren

Jetzt Blog abonnieren!

Kommentare

Michael Twelkemeier

Michael Twelkemeier

Michael Twelkemeier ist Senior-Berater bei der viadee. Er berät Kunden im Finanzdienstleistungs-Umfeld in Fragen der IT-Architektur und Systemintegration bei der Umsetzung individueller Softwaresysteme mit einem Schwerpunkt auf Java-basierte Enterprise-Anwendungen.

Er ist Leiter des Kompetenzbereichs Java / Software-Architektur und teilt seine Erfahrungen als Autor und Speaker u.a. auf dem NAVIGATE Kongress.

Michael Twelkemeier bei Xing Michael Twelkemeier bei LinkedIn