Unsere Lösungen,
ob Start-Up oder etabliertes Unternehmen

Business Process Management

Java

Testautomatisierung

Agile Methoden

Mobile- und Weblösungen

Business-Intelligence

vivir

IT-Sicherheit

Künstliche Intelligenz

viadee Themen

In unserem Blog finden Sie Fachartikel, Success-Stories, News, Messeberichte und vieles mehr... vor allem aber hoffentlich wertvolle Informationen, die Ihnen in Ihrem konkreten Projekt und in Ihrem Business weiterhelfen. Bei Fragen und Anregungen nehmen Sie gerne Kontakt zu uns auf. Bitte benutzen Sie dazu die Kommentarfunktion unter den Blogbeiträgen.

JAXB und SOAP in JAVA 11

19.11.18 14:32

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.

 

JAXB und SOAP in JAVA 11
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:
JAXB und SOAP in Java 11
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:
JAXB und SOAP in Java 11

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.


Jetzt Blog abonnieren!
zum Blog
Michael Twelkemeier

Michael Twelkemeier

Michael Twelkemeier ist IT Berater und Software Architekt bei der viadee. Sein Fokus liegt auf dem Design und der Entwicklung von Java/Spring-basierten Enterprise Anwendungen. Dabei ist es ihm wichtig, Konzeption und Umsetzung nicht getrennt zu betrachten, sondern eine Brücke zwischen beiden herzustellen, um optimierte Lösungen zu erzielen.