Kriterien für die Auswahl eines "XML Data Binding"-Frameworks

Wie lassen sich unterschiedliche XML-Data-Binding-Frameworks miteinander vergleichen, und wie wählt man das richtige aus? "heise Developer" bietet Kriterien hierfür, die als erster Leitfaden dienen können.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 20 Min.
Von
  • Thilo Frotscher
  • Alexander Neumann
Inhaltsverzeichnis

Insbesondere für den Datenaustausch und die Integration von Systemen hat sich XML breit durchgesetzt. Bei der Anwendungsentwicklung ist der Umgang mit XML-Dokumenten durch ihre baumartige Struktur in vielen Fällen jedoch umständlich. Viel lieber möchte man mit fachlichen Klassen arbeiten, die sich mit den Daten eines XML-Dokuments oder einer XML-Nachricht befüllen lassen. Daraus resultiert, dass die Umwandlung zwischen XML und fachlichen Objekten eine häufig wiederkehrende Anforderung darstellt.

Im Sprachgebrauch existieren für diese Umwandlung mehrere Begriffe. Manchmal spricht man von Serialisierung und Deserialisierung, etwas verbreiteter sind die Ausdrücke Marshalling und Unmarshalling. Als generellen Überbegriff trifft man oft auf XML Data Binding.

Die erforderlichen Funktionen hierfür kann man selbst implementieren, und nicht wenige Entwicklerteams haben sich in der Vergangenheit daran versucht. Recht bald kommt man aber zur Erkenntnis, dass diese Aufgabe weitaus komplexer ist, als man fürs Erste angenommen hat. Glücklicherweise gibt es hierfür im Java-Bereich eine beträchtliche Anzahl Frameworks. Das Rad neu zu erfinden ist also nicht nötig. Dafür stehen Entwickler vor einer anderen Herausforderung, nämlich das richtige Framework auszuwählen.

Wie lassen sich unterschiedliche XML-Data-Binding-Frameworks miteinander vergleichen, und wie wählt man das richtige aus? Ein pragmatischer Ansatz besteht darin, einen Kriterienkatalog über die Anforderungen an die gesuchte Lösung zu erstellen. Die Kriterien sollten im Idealfall priorisiert sein. Es ist jedoch zu betonen, dass es keinen allgemein gültigen Katalog geben kann. Ebenso wenig lässt sich eine generelle Empfehlung für oder gegen ein bestimmtes Framework aussprechen. Stattdessen ist der Einzelfall mit all seinen spezifischen Anforderungen und Einschränkungen zu betrachten. Die folgenden Kriterien können aber als erster Leitfaden dienen.

XML-Schema-Unterstützung: Die meisten Anwendungen verwenden Schemata, um die Struktur gültiger XML-Dokumente zu definieren. Diese sind insbesondere nützlich, wenn empfangene Dokumente oder Nachrichten auf ihre Gültigkeit zu prüfen sind. XML Schema ist nicht nur eine komplexe, sondern auch eine mächtige Spezifikation. Der Standard kann unter anderem Datenstrukturen definieren, die in gängigen Programmiersprachen keine direkte Entsprechung haben. Als Grundregel gilt daher: Je komplizierter man ein Schema definiert beziehungsweise je mehr Funktionen der XML-Schema-Spezifikation man verwendet, desto schwieriger ist es, ein Framework zu finden, das alle diese Features unterstützt.

Code-Generierung: Viele Frameworks arbeiten so, dass ein Code-Generator von einem XML Schema aus Klassen erzeugt, welche die im Schema definierten Typen und Elemente repräsentieren. Wenn entweder ein Framework oder die Zielsprache einzelne im Schema verwendete Konstrukte nicht unterstützt, sind Schwierigkeiten vorprogrammiert. Scheinbar einfache Konstrukte wie choice oder union sind bekannte Problemquellen. Manche Frameworks verfolgen dagegen alternative Ansätze ohne Code-Generierung. In diesen Fällen können oder müssen (das ist Geschmackssache) Entwickler die fachlichen Klassen selbst implementieren.

Code-Abhängigkeiten: Generiert man Code aus einem Schema, lohnt ein genauer Blick auf das Ergebnis. Hier offenbaren sich große Unterschiede zwischen den Frameworks. In manchen Fällen handelt es sich bei den generierten fachlichen Klassen um reine POJOs (Plain Old Java Objects). Das (Un)Marshalling lässt sich "von außen" durchführen, entweder mit dem Framework oder mit ebenfalls generierten Hilfsklassen. Andere Frameworks erzeugen dagegen keine reinen POJOs, sondern fachliche Klassen, die zusätzlich eine Menge frameworkspezifischen Code enthalten. Es kann sich beispielsweise um Factory-Methoden handeln oder eben um Code, der das (Un)Marshalling von Instanzen direkt in den jeweiligen Klassen implementiert. Will man das verwendete Framework eines Tages austauschen, bedeuten solche Code-Abhängigkeiten einen erheblichen Mehraufwand.

Vererbung: Eng verknüpft mit dem vorausgegangenen Punkt ist die Frage, inwieweit ein verwendetes Framework den Entwickler beim objektorientierten Design einschränkt. Generiert man fachliche Klassen aus einem XML Schema, lassen sich Vererbungshierarchien nur bedingt einsetzen. XML Schema erlaubt es zwar, Typen von anderen abzuleiten, auf diesem Weg lassen sich jedoch nur Properties in einer Superklasse unterbringen, allerdings kein fachlicher Code. Zudem sind die generierten Klassen bei manchen Lösungen grundsätzlich von einer Framework-Klasse abgeleitet, was fachlich bedingte Vererbung ausschließt.

Natürlichkeit der API: Wurde ein Framework gewählt, das die fachlichen Klassen generiert, so möchten man diese Klassen dennoch genauso verwenden können wie ganz normale POJOs. Das gilt auch dann, wenn die generierten Klassen frameworkspezifischen Code enthalten. Insbesondere bedeutet dies, dass neue Instanzen mit new-Operatoren zu erstellen und ihre Properties über get/set-Methoden zugänglich sind. Bei manchen Frameworks ist das nicht der Fall. Als Folge muss man sich bei der Anwendungsentwicklung an teilweise recht unnatürlich anmutende APIs gewöhnen.

Java-1.4-Support: Ein weiteres Auswahlkriterium dürfte in vielen Umgebungen sein, ob ein Framework unter Java 1.4.x einzusetzen ist. Noch immer sind ältere Versionen von Applikationsservern recht weit verbreitet, die maximal Java 1.4 unterstützen. Insbesondere solche Frameworks, die Annotationen verwenden, scheiden in diesen Umgebungen daher aus.

Performanz: Ein wichtiges, erstaunlicherweise aber häufig vernachlässigtes Kriterium ist die Performanz der XML-Data-Binding-Lösung. Insbesondere in einer Webservice-Anwendung kann sie einen gewaltigen Unterschied ausmachen. Da das XML Data Binding typischerweise beim Versand und beim Empfang von Nachrichten zum Einsatz kommt, und zwar sowohl auf Seiten des Senders als auch beim Empfänger, sind bei einer typischen Request-Response-Operation also insgesamt vier (Un)Marshallings notwendig. Oft schauen Entwickler bei Performanzproblemen auf das Webservice-Framework. Hier sind die Unterschiede inzwischen aber überwiegend gering. Die Wahl eines besser geeigneten XML Data Binding kann dagegen Wunder wirken. Im Web sind zwar unterschiedliche Benchmarks zu finden, diese sind jedoch – wie meist – mit gewisser Vorsicht zu genießen.

Verwendeter Parser: Über die Jahre hinweg hat sich die Parser-Technik weiterentwickelt. So existieren heute mit DOM, SAX und StAX gleich drei verbreitete Parsing-Ansätze mit unterschiedlichen Stärken und Schwächen. DOM Parser (Document Object Model) bauen während des Parsens von XML-Dokumenten eine baumartige Struktur im Speicher auf, welche die Struktur des Dokuments widerspiegelt. Die große Stärke von DOM liegt darin, dass man anschließend komfortabel zwischen den einzelnen Knoten navigieren kann. Ein wesentlicher Nachteil liegt dagegen in der Performanz. Unter Last wird der Aufbau der Baumstrukturen oftmals zum Flaschenhals, insbesondere beim benötigten Arbeitsspeicher. Im Bereich der Webservice-Anwendungen kommt hinzu, dass wichtige Metainformationen (zum Beispiel zur Authentifizierung) im Nachrichten-Header untergebracht sind. Selbst wenn diese Informationen am Anfang der Nachricht zur Folge haben, dass die Nachricht abgelehnt wird, ist beim DOM-Ansatz dennoch zunächst die gesamte Nachricht zu parsen. Somit verschenkt man viele Ressourcen. Daher hat sich gerade im Bereich von Webservices der Einsatz von Streaming-Parsern durchgesetzt. Wie der Name vermuten lässt, verarbeitet man XML-Dokumente hier strombasiert, d.h. Zeichen für Zeichen. Während dies eine vergleichsweise nur eingeschränkte Navigation erlaubt, ergibt sich in der Regel eine deutlich bessere Performanz unter Last. Bei der älteren SAX-Variante (Simple API for XML) liegt die Ablaufkontrolle beim Parser. Findet dieser ein neues Element im Datenstrom, lassen sich entsprechende Handler aufrufen, die vom Anwendungsentwickler zu implementieren sind. Die neuere StAX-Variante (Streaming API for XML) dreht diese Kontrolle herum. Nun hat der Entwickler wieder das Zepter in der Hand und instruiert den Parser, im Datenstrom nach bestimmten Bestandteilen eines Dokuments zu suchen. Insbesondere lässt sich der Parsing-Vorgang jederzeit abbrechen, falls feststeht, dass der restliche Teil eines Dokuments nicht mehr von Interesse ist. Bei der Auswahl einer XML-Data-Binding-Lösung ist demnach gegebenenfalls zu betrachten, welche Parser-Variante unter der Haube verwendet wird.

Verlustfreie Umwandlung: XML-Dokumente und Nachrichten enthalten oft mehr Informationen, als fachliche Klassen benötigen. Es handelt sich beispielsweise um Kommentare oder Zusatzelemente. Viele XML-Data-Binding-Frameworks ignorieren diese Zusatzinformationen. Hieraus resultiert folgendes Phänomen: Wandelt man ein XML-Dokument in ein Objekt um und unmittelbar danach das Objekt wieder in XML, so sind das ursprüngliche und das resultierende XML-Dokument häufig voneinander verschieden. Während das in manchen Anwendungen kein Problem darstellt, führt es in anderen zu großen Kopfschmerzen. Berechnet man etwa Prüfsummen für XML-Dokumente, beispielsweise im Zusammenhang mit digitalen Signaturen, ist ein solches Verhalten nicht akzeptabel. Selbst eine unterschiedliche Formatierung der Dokumente oder eine unterschiedliche Reihenfolge von Attributen beziehungsweise Elementen führt zu großen Schwierigkeiten. Hier ist eine Lösung notwendig, die eine verlustfreie Umwandlung ermöglicht und das ursprüngliche XML Infoset erhält.

Bei einer Sondierung verfügbarer Alternativen fällt sehr schnell auf, dass die Auswahl außerordentlich unübersichtlich ist. Mit einer Suchmaschine lassen sich in relativ kurzer Zeit gleich mehrere Dutzend XML-Data-Binding-Frameworks für Java finden. Da ist es fast unnötig zu erwähnen, dass diese zum Teil sehr unterschiedliche Ansätze verfolgen. Natürlich hat jedes Framework seine spezifischen Stärken und Schwächen. Der Artikel betrachtet eine kleine Auswahl von vier recht unterschiedlichen Vertretern, um die Breite des Angebots zu veranschaulichen.

An erster Stelle ist JAXB (Java Architecture for XML Binding) zu nennen. Es stellt sozusagen die Standardlösung dar, da es seit Java 6 integraler Bestandteil des Java SDK (Software Development Kit) ist. Zudem ist es Bestandteil von Java EE 5, benötigt aber zur Ausführung mindestens Java SE 5. Inzwischen liegt JAXB in einer ausgereiften Version 2.x vor, es ist aber nicht automatisch die beste Lösung. Das ist unter anderem dadurch begründet, dass JAXB stark auf dem Einsatz von Annotationen beruht. In Umgebungen, in denen Java 5 (noch) nicht eingesetzt werden kann, scheidet JAXB daher als Alternative aus.

Liegt ein XML Schema vor, so lässt sich der JAXB Binding Compiler verwenden, um Java-Code für die darin definierten Typen und Elemente zu generieren. Dieser Code ist mit den entsprechenden Annotationen angereichert. Die JAXB-Laufzeitbibliothek stellt Methoden für unterschiedliche (Un)Marshalling-Varianten zur Verfügung. Unter anderem unterstützt JAXB die Verwendung von SAX. Alternativ lässt sich auch ohne Code-Generator arbeiten. In diesem Fall sind die fachlichen Klassen selbst zu implementieren und mit den notwendigen Annotationen anzureichern. Hier bietet JAXB einiges an Flexibilität. Beispielsweise lässt sich über Annotationen festlegen, ob eine Property beim Umwandeln in XML als Element oder als Attribut abzubilden ist. Mit einer anderen Annotation ist zu bestimmen, wie sich ein bestimmter Java-Typ auf einen XML-Schema-Typ abbilden lässt. Nach Implementierung der benötigten Klassen kann der Entwickler mit dem JAXB-Schema-Generator ein passendes Schema generieren. Seit Version 2.x bietet JAXB vollen XML-Schema-Support.

Ein populäres XML-Framework der vergangenen Jahre war sicherlich Apache XMLBeans. Es wurde 2003 von BEA entwickelt und wenig später an die Apache Software Foundation (ASF) übergeben. XMLBeans ist bis heute in manchen Disziplinen konkurrenzlos, während es in anderen ein wenig von den neuen technischen Entwicklungen überholt zu sein scheint. Eine der Stärken des Frameworks liegt in der traditionell guten Unterstützung von XML Schema. Zwar haben konkurrierende Frameworks mit der Zeit aufgeholt. Generell darf aber weiterhin gelten: Je komplexer ein XML Schema, desto geringer ist die Anzahl der Frameworks, die diese verwendeten Schema-Features unterstützt. XMLBeans ist in komplizierten Fällen oft der einzige Vertreter, der zum Erfolg führt. Darüber hinaus erhält das Framework beim Parsen das XML Infoset. Dieses ist also nicht nur nach dem Unmarshalling zur Laufzeit zugänglich, sondern lässt sich insbesondere wieder herstellen, wenn eine Rückumwandlung nach XML erfolgt. Minuspunkte sammelt XMLBeans dagegen bei vielen Entwicklern auf Code-Ebene. Für alle in einem Schema definierten Typen und Elemente generiert XMLBeans sowohl eine Klasse als auch ein Interface, die jeweils von einer Klasse (XmlObject) beziehungsweise einem Interface des Frameworks abgeleitet sind. Es ergeben sich also erhebliche Code-Abhängigkeiten zwischen den fachlichen Klassen und XMLBeans. Zudem fühlt sich das Erzeugen und Befüllen von Instanzen ungewöhnlich an. Statt des new-Operators sind beispielsweise Factories zu verwenden. Komplexe Properties lassen sich mit einer add-Methode befüllen.

Als besonderes Feature bietet XMLBeans gleich drei APIs an: Neben dem Zugriff auf alle im Schema definierten Elemente über XmlObject lässt sich ein XmlCursor anfordern, der einen effizienten Zugriff auf das XML Infoset ermöglicht. Schließlich erlaubt SchemaType den Zugriff auf die zugrunde liegenden Schema-Metainformationen eines Objekts. Beispielsweise sind so die erlaubten Werte einer Enumeration herauszufinden und lassen sich etwa in einer Auswahlbox anzeigen. XMLBeans benötigt keine Java-5-Sprachfeatures.

Insbesondere durch den großen Erfolg der Webservice-Techniken und die damit einhergehende Verbreitung von XML-Kommunikationsprotokollen entstand eine Vielzahl recht neuer XML-Data-Binding-Lösungen. Manche, aber nicht alle dieser Entwicklungen sind eng mit einem Webservice-Framework verbunden. Hier ist ADB (Axis Data Binding) zu nennen, das Bestandteil von Apache Axis2, aber auch davon unabhängig einzusetzen ist.

ADB basiert auf einem ebenfalls ursprünglich für Axis2 entwickelten Objektmodell namens AXIOM. Eines der Hauptziele bei der Entwicklung von AXIOM war das Erreichen einer guten Performanz. Gleichzeitig sollte es möglich sein, die Verarbeitung von SOAP-Nachrichten sofort abzubrechen, falls eine Nachricht aufgrund des Inhalts ihres Headers abzulehnen ist. Aus diesen Gründen wurde ein StAX-Parser ausgewählt. Gleichzeitig wollte man das Problem lösen, dass mit Stream-Parsern keine so komfortable Navigation möglich ist wie mit DOM. AXIOM löst das mit einer cleveren Idee: Es bietet eine DOM-basierte API als Schale um den StaX-Parser. So können Entwickler zwar wie in einem Baum navigieren, der Baum baut sich jedoch nicht automatisch und im Voraus im Speicher auf, sondern nur nach Bedarf – je nachdem wann und auf welchen Knoten der Entwickler zur Laufzeit navigiert. Will man beispielsweise einen Kindknoten besuchen, weist das Framework den Parser an, den Datenstrom so weit zu parsen, bis die notwendigen Informationen vorliegen. Dieses Vorgehen nennt man "deferred parsing". AXIOM bringt gute Performanz mit einfacher Navigation in Einklang und stellte sich als vielseitig einsetzbar heraus, sodass es inzwischen ein eigenständiges Apache-Projekt ist.

Die von ADB aus einem Schema generierten AXIOM-Klassen enthalten frameworkspezifischen Code für das (Un)Marshalling. Mit einem Schalter des Code-Generators ist dieser Code jedoch in eine externe Hilfsklasse auszulagern, sodass reine POJOs entstehen. ADB arbeitet auch mit Java 1.4.x. Die XML-Schema-Unterstützung ist nicht vollständig, die Entwickler haben sie in der Vergangenheit aber stetig verbessert und sie sollte in der Praxis für die meisten Schemata inzwischen ausreichend sein.

Zu guter Letzt ist das bislang noch relativ unbekannte JiBX zu erwähnen. Das Framework unterscheidet sich in einigen Punkten erheblich von den bislang vorgestellten Lösungen. So definiert es die Abbildungsregeln zwischen XML und Java-Klassen mit einer Mapping-Datei, ähnlich wie Hibernate. Hierdurch ist JiBX flexibel: Während andere Frameworks in aller Regel jedes in einem Schema definierte Element oder jeden Typ auf genau eine Klasse abbilden, lassen sich mit Mapping-Regeln beliebige Abbildungen definieren. Zum Beispiel lässt sich der Inhalt eines Elements beim Unmarshalling auf unterschiedliche Objekte verteilen und umgekehrt. Eine weitere Besonderheit von JiBX ist das Umsetzen der eigentlichen (Un)Marshalling-Funktionen per Bytecode-Enhancement. Das bedeutet, dass der Sourcecode vollkommen davon unberührt bleibt. Nach der Kompilierung mit dem Java-Compiler erfolgt jedoch ein zweiter Kompilierschritt. Dabei reichert der JiBX-Compiler die vom Java-Compiler erstellten Bytecode-Dateien um die notwendigen Funktionen an. Die genauen Anweisungen hierfür werden aus der Mapping-Datei entnommen. Moderne IDEs erlauben es, diesen zusätzlichen automatisierten Build-Schritt einmalig für ein Projekt einzurichten. Zur Laufzeit arbeitet der angereicherte Code mit einer JiBX-Runtime-Komponente zusammen, die das Framework in Form einer JAR-Datei bereitstellt.

Ursprünglich brachte JiBX keinen Code-Generator mit, der fachliche Klassen aus einem XML Schema erstellt. Stattdessen waren diese Klassen selbst zu implementieren und eine zugehörige Mapping-Datei zu erstellen. Während das bei Neuentwicklungen hier und da als lästige Fleißarbeit empfunden werden könnte, sind andere Entwicklerteams froh, dass sie bestehende Klassen ohne Änderung wiederverwenden können. So entsteht auch nicht das bekannte Phänomen, "doppelte" Klassen für die gleichen Konzepte zu haben: die selbst implementierten Klassen und jene, die man aus einem Schema generiert. Ebenso können beliebige Vererbungshierarchien implementiert sein, all dies spielt für den Einsatz von JiBX keine Rolle.

Inzwischen gibt es einige neue Tools für JiBX, die es erlauben, von einem XML Schema aus sowohl Java-Code als auch eine zugehörige Mapping-Datei automatisch zu generieren. Alternativ lässt sich anders herum arbeiten und eine Mapping-Datei und ein XML Schema aus bestehendem Code erzeugen.

JiBX punktet bei vielen Kriterien. Es vereint maximale Binding-Flexibilität mit der Möglichkeit, bestehende fachliche Klassen ohne Änderung wiederzuverwenden, und das ohne Code-Abhängigkeiten zum Framework und ohne Probleme mit komplizierten Schema-Features. Das Framework erfordert keine Java-5-Sprachfeatures, und zu alledem schlägt es in puncto Performanz den Großteil seiner Konkurrenz recht deutlich. Aufgrund dieser Stärken erfreut sich JiBX zunehmender Beliebtheit. Als Nachteil sieht man hier und dort, dass das Framework (noch) nicht verbreitet ist und ein vergleichsweise kleines Entwicklerteam es vorantreibt.

Die weite Verbreitung von XML in unterschiedlichen Bereichen der Software-Entwicklung hat dafür gesorgt, dass XML Data Binding ein wichtiges Thema ist. Die Vergangenheit hat gezeigt, dass es sich um eine Aufgabe handelt, die weitaus schwieriger ist, als sie bei flüchtiger Betrachtung erscheinen mag. Ein Hauptgrund hierfür liegt sicherlich in der Komplexität von XML Schema. Da sich über die Jahre ein reiches Angebot von teils mächtigen Frameworks entwickelt hat, besteht kein Grund mehr, all diese Funktionen selbst zu implementieren. Stattdessen sollten Entwickler ausreichend Zeit und Anstrengung in die Frage investieren, welche der zur Wahl stehenden Lösungen die Anforderungen einer spezifischen Anwendung am besten umsetzt. Leider ist häufig zu beobachten, dass Projekte die Auswahl praktisch nebenbei treffen, was unangenehme Überraschungen zur Folge haben kann.

In der Praxis hat sich bewährt, eine Liste mit priorisierten Kriterien aufzustellen und eine Vorauswahl von Frameworks anhand dieser Liste zu vergleichen. Die im Verlauf des Artikels genannten Kriterien können als roter Faden dienen, sind jedoch in der Regel durch projekt- oder unternehmensspezifische Anforderungen zu ergänzen. Wie die kurze Vorstellung von JAXB, XMLBeans, ADB und JiBX gezeigt hat, stehen zum Teil sehr unterschiedliche Ansätze zur Verfügung. Es ist auf alle Fälle lohnenswert, sich auch darüber hinaus ein wenig umzuschauen.

Thilo Frotscher
ist freiberuflicher Softwarearchitekt und Trainer. Als Experte für Java, Webservices und SOA unterstützt er seine Kunden durch die Mitarbeit in Projekten und die Durchführung von Schulungen oder Reviews. Thilo ist Autor unterschiedlicher Bücher im Webservices- und SOA-Umfeld sowie zahlreicher Artikel für Fachzeitschriften. Darüber hinaus wirkt er als Fachgutachter für Publikationen im Bereich Webservices und XML und berichtet regelmäßig auf internationalen Fachkonferenzen über seine Erfahrungen.
(ane)