JAX B
Upcoming SlideShare
Loading in...5
×
 

JAX B

on

  • 4,873 views

 

Statistics

Views

Total Views
4,873
Views on SlideShare
4,873
Embed Views
0

Actions

Likes
1
Downloads
95
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    JAX B JAX B Document Transcript

    • Michaelis/Schmiesing JAXB 2.0 Ein Programmiertutorial für die Java Architecture for XML Binding              
    • Samuel Michaelis Wolfgang Schmiesing JAXB 2.0 Ein Programmiertutorial für die Java Architecture for XML Binding
    • Die Autoren: Samuel Michaelis, Software-Architekt Wolfgang Schmiesing, Berater und Projektleiter Beide Autoren sind für die Innovations Softwaretechnologie GmbH in Immenstaad tätig. Alle in diesem Buch enthaltenen Informationen, Verfahren und Darstellungen wurden nach bestem Wissen zusammengestellt und mit Sorgfalt getestet. Dennoch sind Fehler nicht ganz auszuschließen. Aus diesem Grund sind die im vorliegenden Buch enthaltenen Informationen mit keiner Verpflich- tung oder Garantie irgendeiner Art verbunden. Autoren und Verlag übernehmen infolgedessen keine juristische Verantwortung und werden keine daraus folgende oder sonstige Haftung übernehmen, die auf irgendeine Art aus der Benutzung dieser Informationen – oder Teilen davon – entsteht. Ebenso übernehmen Autoren und Verlag keine Gewähr dafür, dass beschriebene Verfahren usw. frei von Schutzrechten Dritter sind. Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbe- zeichnungen usw. in diesem Buch berechtigt deshalb auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten wären und daher von jedermann benutzt werden dürften. Bibliografische Information Der Deutschen Nationalbibliothek Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar. Dieses Werk ist urheberrechtlich geschützt. Alle Rechte, auch die der Übersetzung, des Nachdruckes und der Vervielfältigung des Buches, oder Teilen daraus, vorbehalten. Kein Teil des Werkes darf ohne schriftliche Genehmigung des Verlages in irgendeiner Form (Fotokopie, Mikrofilm oder ein anderes Verfahren) – auch nicht für Zwecke der Unterrichtsgestaltung – reproduziert oder unter Verwendung elektronischer Systeme verarbeitet, ver- vielfältigt oder verbreitet werden. © 2007 Carl Hanser Verlag München Wien Lektorat: Fernando Schneider Sprachlektorat: Sandra Gottmann, Münster-Nienberge Herstellung: Monika Kraus Umschlagdesign: Marc Müller-Bremer, Rebranding, München Umschlaggestaltung: MCP · Susanne Kraus GbR, Holzkirchen Datenbelichtung, Druck und Bindung: Kösel, Krugzell Ausstattung patentrechtlich geschützt. Kösel FD 351, Patent-Nr. 0748702 Printed in Germany ISBN-10: 3-446-40753-7 ISBN-13: 978-3-446-40753-4 www.hanser.de/computer
    • Inhalt Vorw Java Architecture for XML Binding 2.0.................................................................................XI Technologieeinführung ........................................................................................................ XII Programmiertutorials............................................................................................................ XII Referenz ............................................................................................................................... XII Feedback ............................................................................................................................. XIII 1 JAXB im Überblick................................................................................................... 1 1.1 Ziele .........................................................................................................................................1 1.2 Entstehung................................................................................................................................4 1.3 Architektur ...............................................................................................................................5 1.3.1 Annotationen ..............................................................................................................7 1.3.2 Der Schema-Compiler ................................................................................................8 1.3.3 Der Schema-Generator ...............................................................................................9 1.3.4 Das Binding Framework...........................................................................................10 1.4 1.0 + 1.0 = 2.0? ......................................................................................................................14 2 Basistechnologien ................................................................................................. 17 2.1 XML-Schema.........................................................................................................................17 2.1.1 Namespaces verwenden............................................................................................21 2.1.2 Elementdeklarationen in XML-Schema ...................................................................24 2.1.3 Vererbung.................................................................................................................35 2.1.4 Kardinalitäten ...........................................................................................................37 2.1.5 Offene Schemas definieren.......................................................................................38 2.1.6 Namespaces importieren und referenzieren..............................................................40 2.1.7 Eindeutigkeit durch ID und IDREF ..........................................................................43 2.1.8 Dokumentation mit Annotationen ............................................................................45 2.1.9 Das fertige Beispielschema ......................................................................................46 V
    • Inhalt 2.2 XPath......................................................................................................................................48 2.2.1 Die XPath-Sicht auf XML........................................................................................49 2.2.2 XPath-Ausdrücke verwenden ...................................................................................50 2.2.3 Beispiele ...................................................................................................................51 2.2.4 XPath in Java............................................................................................................53 2.3 ANT .......................................................................................................................................55 2.3.1 ANT-Übersicht .........................................................................................................55 2.3.2 Installation und Aufruf .............................................................................................56 2.3.3 Häufig verwendete Elemente....................................................................................57 2.3.4 Benutzerdefinierte Tasks ..........................................................................................58 2.3.5 xjc und schemaGen Tasks ........................................................................................58 2.3.6 Ein Beispiel ..............................................................................................................59 3 Hallo JAXB! ............................................................................................................ 61 3.1 Systemvoraussetzungen .........................................................................................................61 3.2 Die Entwicklungsumgebung einrichten..................................................................................62 3.2.1 JAXB-Referenzimplementierung installieren...........................................................62 3.2.2 Die JAXB-Bibliotheken einbinden...........................................................................62 3.2.3 Die Struktur des Beispielprojekts .............................................................................63 3.3 Am Anfang steht immer: Hallo Welt! ....................................................................................64 3.3.1 Der Weg von Java zu XML ......................................................................................64 3.3.2 Der Weg von XML zu Java ......................................................................................67 3.4 Zusammenfassung..................................................................................................................69 4 JAXB-API ................................................................................................................ 71 4.1 Die ersten Schritte ..................................................................................................................72 4.1.1 Am Anfang war der JAXBContext...........................................................................72 4.1.2 Die Klasse JAXBIntrospector verwenden ................................................................75 4.1.3 Objekte erzeugen mit der ObjectFactory ..................................................................77 4.1.4 Zusammenfassung ....................................................................................................78 4.2 Marshalling ............................................................................................................................79 4.2.1 Das Marshaller-Objekt anlegen ................................................................................79 4.2.2 Den Marshalling-Prozess starten ..............................................................................80 4.2.3 Den Marshalling-Prozess konfigurieren ...................................................................81 4.2.4 Das fertige Beispiel ..................................................................................................83 4.2.5 Marshalling beliebiger Objekte ................................................................................85 4.2.6 Zusammenfassung ....................................................................................................86 4.3 Unmarshalling ........................................................................................................................87 4.3.1 Das Unmarshaller-Objekt anlegen............................................................................87 4.3.2 Den Unmarshalling-Prozess starten..........................................................................88 4.3.3 Den Unmarshalling-Prozess konfigurieren...............................................................89 4.3.4 Das fertige Beispiel ..................................................................................................89 4.3.5 Das xsi:type-Attribut beim Unmarshalling verwenden.............................................90 4.3.6 Elemente ohne @XMLRootElement verarbeiten .....................................................91 4.3.7 Unmarshalling von Teilen eines XML-Dokuments ..................................................93 4.3.8 Flexibles Unmarshalling nutzen ...............................................................................95 VI
    • Inhalt 4.3.9 Zusammenfassung ................................................................................................... 97 4.4 Validierung............................................................................................................................ 97 4.4.1 Beim Unmarshalling validieren ............................................................................... 98 4.4.2 Beim Marshalling validieren.................................................................................... 99 4.4.3 Benutzerdefinierte Validierung.............................................................................. 101 4.4.4 Zusammenfassung ................................................................................................. 107 4.5 Callback-Mechanismen einsetzen ....................................................................................... 107 4.5.1 Die Listener-Klasse verwenden ............................................................................. 108 4.5.2 Callback-Methoden auf Klassenebene definieren.................................................. 110 4.5.3 Zusammenfassung ................................................................................................. 112 4.6 Die Binder-Komponente verwenden ................................................................................... 112 4.6.1 Eine DOM-Sicht erstellen...................................................................................... 113 4.6.2 Die Klasse javax.xml.bind.Binder ......................................................................... 113 4.6.3 Transformation mit unmarshal und marshal .......................................................... 114 4.6.4 Navigation mit getXMLNode und getJAXBNode................................................. 115 4.6.5 Synchronisation mit updateXML und updateJAXB .............................................. 116 4.6.6 Konkrete Anwendungsfälle ................................................................................... 117 4.6.7 Zusammenfassung ................................................................................................. 123 5 XML-Schema zu Java .......................................................................................... 125 5.1 Bindungskonfigurationen .................................................................................................... 125 5.1.1 Eine Bindungskonfiguration definieren ................................................................. 126 5.1.2 Bindungskonfigurationen per xjc-Task einbinden ................................................. 130 5.1.3 Den XJC-Schema-Compiler programmatisch starten ............................................ 130 5.1.4 Externe Bindungskonfigurationen auf der Kommandozeile .................................. 134 5.1.5 Ein Wort zu Versionen .......................................................................................... 134 5.1.6 Der Sichtbarkeitsbereich........................................................................................ 134 5.1.7 Zusammenfassung ................................................................................................. 135 5.2 Die erste Bindungskonfiguration......................................................................................... 136 5.2.1 Zusammenfassung ................................................................................................. 138 5.3 Fünf Bindungsdeklarationen für den Alltag ........................................................................ 138 5.3.1 Aufzählungen anpassen mit jaxb:collectionType................................................... 138 5.3.2 Paketnamen anpassen mit jaxb:package ................................................................ 140 5.3.3 Generierte Klassen anpassen mit jaxb:class........................................................... 142 5.3.4 Änderungen auf Komponentenebene mit jaxb:property ........................................ 145 5.3.5 Dokumentieren mit jaxb:javadoc ........................................................................... 152 5.3.6 Zusammenfassung ................................................................................................. 155 5.4 XML-Bezeichner anpassen.................................................................................................. 155 5.4.1 Einzelne Namenskonflikte auflösen....................................................................... 156 5.4.2 Präfixe und Suffixe mit jaxb:nameXmlTransform................................................. 157 5.4.3 Unterstriche verarbeiten mit jaxb:underScoreBinding........................................... 159 5.4.4 Bezeichner in Enumerationen ................................................................................ 160 5.4.5 Verwenden von Java-Schlüsselwörtern als Bezeichner ......................................... 166 5.4.6 Java-Namenskonventionen .................................................................................... 168 5.4.7 Zusammenfassung ................................................................................................. 168 5.5 Datentypen anpassen ........................................................................................................... 168 VII
    • Inhalt 5.5.1 Datentypen explizit angeben mit jaxb:baseType ....................................................169 5.5.2 Datentypen konvertieren mit jaxb:javaType...........................................................173 5.5.3 Zusammenfassung ..................................................................................................181 5.6 Deklarationen überlagern .....................................................................................................182 5.7 Noch mehr Bindungsdeklarationen ......................................................................................185 5.7.1 Ableiten von einer Oberklasse mit xjc:superClass..................................................186 5.7.2 Ein Wurzelinterface angeben mit xjc:superInterface ..............................................187 5.7.3 Erweiterung von jaxb:javaType mit xjc:javaType ..................................................189 5.7.4 Das Experiment: xjc:simple....................................................................................191 5.7.5 Zusammenfassung ..................................................................................................192 6 Java zu XML-Schema .......................................................................................... 193 6.1 JAXBContext und JAXBElement ganz ohne Schema..........................................................194 6.2 Einfache Elementkonfigurationen ........................................................................................201 6.2.1 Wurzelelemente mit @XmlRootElement definieren ..............................................201 6.2.2 Der „Standardmodus“.............................................................................................205 6.2.3 Abbildung als XML-Element explizit konfigurieren ..............................................210 6.2.4 Java-Eigenschaften an XML-Attribute binden .......................................................216 6.2.5 Java-Eigenschaften an XML-Elementinhalte binden..............................................221 6.2.6 Bindung an XML unterdrücken..............................................................................223 6.2.7 Reihenfolge der XML-Elemente beeinflussen........................................................225 6.2.8 Namen und Verschachtelung des XML-Typs einstellen.........................................230 6.2.9 XML-Elemente referenzieren .................................................................................234 6.2.10 Namespace konfigurieren .......................................................................................237 6.3 Listen und Elementmischungen ...........................................................................................243 6.3.1 Der „Standardmodus“ für Java-Arrays und Java-Listen .........................................244 6.3.2 Listen und Arrays an simpleType/list-Deklarationen binden..................................249 6.3.3 Mehrere Elemente im gleichen Feld speichern.......................................................251 6.3.4 Elementlisten verpacken.........................................................................................263 6.3.5 Mischungen von Elementen und Text ....................................................................266 6.4 Enumerationen .....................................................................................................................270 6.4.1 Enumerationen an XML binden: Standardverhalten...............................................271 6.4.2 Bindung von Enumerationen konfigurieren............................................................272 6.5 Eigene Typbindungen definieren .........................................................................................275 6.5.1 Basisdatentyp als Speicherdatentyp........................................................................277 6.5.2 Komplexe Datentypen als Speicherdatentypen.......................................................280 6.6 Unbekannte Attribut- und Elementwerte binden ..................................................................284 6.6.1 Wildcard-Attribute mit @XmlAnyAttribute definieren..........................................284 6.6.2 Wildcard-Elemente per @XmlAnyElement deklarieren ........................................286 6.6.3 Lax fischen .............................................................................................................288 6.7 Objektgraphen in XML abbilden..........................................................................................290 6.8 Elemente über Factory-Klassen definieren...........................................................................295 7 JAXB-Referenz..................................................................................................... 299 7.1 XJC Kommandozeilenbefehl ...............................................................................................299 7.2 XJC ANT-Task ....................................................................................................................301 VIII
    • Inhalt 7.3 schemaGen-Kommandozeilenbefehl ................................................................................... 303 7.4 schemaGen-ANT-Task........................................................................................................ 304 7.5 JAXB-Annotationen............................................................................................................ 306 7.5.1 XmlAccessorOrder ................................................................................................ 306 7.5.2 XmlAccessorType ................................................................................................. 307 7.5.3 XmlAnyAttribute................................................................................................... 311 7.5.4 XmlAnyElement .................................................................................................... 312 7.5.5 XmlAttachmentRef................................................................................................ 314 7.5.6 XmlAttribute.......................................................................................................... 314 7.5.7 XmlElement........................................................................................................... 316 7.5.8 XmlElementDecl ................................................................................................... 318 7.5.9 XmlElementRef ..................................................................................................... 320 7.5.10 XmlElementRefs.................................................................................................... 321 7.5.11 XmlElements ......................................................................................................... 323 7.5.12 XmlElementWrapper ............................................................................................. 324 7.5.13 XmlEnum .............................................................................................................. 325 7.5.14 XmlEnumValue ..................................................................................................... 326 7.5.15 XmlID.................................................................................................................... 327 7.5.16 XmlIDREF............................................................................................................. 328 7.5.17 XmlInlineBinaryData............................................................................................. 330 7.5.18 XmlList.................................................................................................................. 330 7.5.19 XmlJavaTypeAdapter ............................................................................................ 331 7.5.20 XmlJavaTypeAdapters........................................................................................... 332 7.5.21 XmlMimeType ...................................................................................................... 333 7.5.22 XmlMixed.............................................................................................................. 333 7.5.23 XmlNs.................................................................................................................... 334 7.5.24 XmlRegistry........................................................................................................... 334 7.5.25 XmlRootElement ................................................................................................... 335 7.5.26 XmlSchema ........................................................................................................... 336 7.5.27 XmlSchemaType ................................................................................................... 338 7.5.28 XmlSchemaTypes.................................................................................................. 339 7.5.29 XmlTransient ......................................................................................................... 340 7.5.30 XmlType................................................................................................................ 341 7.5.31 XmlValue............................................................................................................... 342 7.6 Typkonversionen Java zu XML-Schema............................................................................. 343 7.7 Typkonversionen XML-Schema zu Java............................................................................. 345 7.8 XML-Elemente der Bindungskonfiguration ........................................................................ 346 7.8.1 Globale Einstellungen............................................................................................ 346 7.8.2 Schemaspezifische Einstellungen .......................................................................... 359 7.8.3 Komponentenspezifische Einstellungen ................................................................ 363 Register............................................................................................................................ 381 IX
    • Vorwort Das Buch wendet sich an Entwickler mit guten Java-Kenntnissen, die in ihrem Arbeitsall- tag oft mit Java und XML arbeiten. In diesem Buch stellen wir mit Suns Java Architecture for XML Binding, kurz JAXB, eine tolle Lösung vor, wie wir dieser Herausforderung effek- tiv begegnen können. Java Architecture for XML Binding 2.0 Wer frühere Versionen der JAXB (1.x) eingesetzt oder evaluiert hat, dem mag die JAXB damals vielleicht verschroben vorgekommen sein. Tatsächlich war die technologische Hürde zum Einsatz von JAXB 1.x sehr hoch. Zum einen waren da die Verwirrungen mit den „endorsed“ XML-Bibliotheken, die Laufzeitfehler verursachten, wenn der Code auf unterschiedlich konfigurierten JVMs ausgeführt wurde – das gute, alte Java-Motto write once, run everywhere traf hier nicht mehr ohne Einschränkungen zu. Zudem waren die JAXB 1.x-Versionen noch nicht inspiriert vom jüngsten Trend zu den POJOs, den Plain Old Java Objects. Hier wurde stattdessen viel mit Factory-Methoden und Schnittstellen herumhantiert, die aus einem Schema ein unnatürliches und unhandliches Java- Datenmodell erzeugten. Von praktischer Bedeutung war in den Versionen bisher nur der Weg von einem XML- Schema zu einem Java-Datenmodell. Ergebnis ist, dass bisherige JAXB-Versionen keine besondere Unterstützung durch Hersteller oder Open-Source-Projekte erfahren haben. Statt dessen entstanden Projekte, die einen natürlicheren Ansatz zur Umwandlung von XML in Java jenseits des JAXB-Standards gesucht und gefunden haben und heute zu den Werk- zeugen der Wahl gehören. Mit der JAXB 2.0 fließen nun diese Ansätze in die JSE zurück: Die Nachteile der bisheri- gen JAXB-Versionen sind wie weggeblasen. Übrig bleibt eine sehr komfortable Art und Weise, aus XML-Schema ein POJO-Datenmodell bzw. aus POJOs ein präzise anpassbares XML-Format zu generieren. Wir sind überzeugt, dass mit der JAXB 2.0 eine Architektur entstanden ist, die für Entwickler eine langfristige und befriedigende Lösung des „XML- und Java“-Themas bringt und durch alle wesentlichen Hersteller und Projekte unterstützt XI
    • Vorwort werden wird. Wir möchten mit diesem Buch einen kleinen Beitrag leisten, diese feine Technologie für alle Entwickler leicht zugänglich machen. Das Buch teilt sich in drei wesentliche Teile auf: Technologieeinführung, Programmiertu- torials und Referenz. Technologieeinführung Der erste Teile beschreibt die der JAXB-Spezifikation zugrunde liegenden Technologien XML-Schema, XPath und Ant im Überblick. Den wichtigsten Anteil übernimmt dabei ein Überblick auf wesentliche Konzepte von XML-Schema. Wir haben im Alltag die Erfah- rung gemacht, dass viele Entwickler XML-Schema zwar sehr gut als „Format zur Be- schreibung von XML-Formaten“ einordnen können und einfache Schemata auch ohne wei- teres verstehen, im konkreten Fall aber gerne nachschlagen, welche Bedeutung einzelne Schemadeklarationen und -konzepte besitzen. Daher bieten wir in diesem Buch eine kleine Einführung in XML-Schema mit dem Ziel, Antworten für die wesentlichen Fragen zu bie- ten, die im Rahmen der Tutorials aufkommen können. Zu den Technologien, die in den Beispielen dieses Buches verwendet werden, gehört auch XPath, das SQL der XML-Welt, und Ant. Auch für diese beiden Technologien bieten wir jeweils eine kleine Darstellung der wesentlichen Möglichkeiten. Programmiertutorials Der zweite Teil des Buches besteht aus vier klassischen Programmiertutorials, welche die verschiedenen Aspekte der JAXB in Beispielen von steigender Komplexität beleuchten. Nach dem obligatorischen „Hallo Welt“-Beispiel folgt eine Einführung in die Laufzeitbib- liothek der JAXB. In Kapitel 5 behandeln wir den Weg von einem XML-Schema zu einem Java-Datenmodell, in Kapitel 6 den Weg von einem Java-Datenmodell zu einem XML- Dokument. Referenz Der dritte Teil ist die Referenz. Wir haben uns zum Ziel gesetzt, dass die Referenz im We- sentlichen für sich alleine stehen kann – so dass ein Entwickler mit guten JAXB- Kenntnissen (die er sich in Programmiertutorial aneignen kann) alle im Alltag aufkom- menden Fragen schnell und insbesondere vollständig anhand der gut strukturierten Refe- renz klären kann. Das hat zur Folge, dass einzelne Informationen in diesem Buch eventuell redundant im Programmiertutorial und in der Referenz vorkommen. Von einem Kommunikationsprofi habe ich mir aber versichern lassen, dass Redundanz, die wir Entwickler im Programmier- XII
    • Vorwort alltag als Code Duplication verteufeln, richtig angewendet im Bereich der Didaktik eine der gerne zitierten Best Practices ist. Wir möchten uns an dieser Stelle bei Ihnen als Leser bedanken, dass Sie dieses Buch und viele weitere durch Ihren beherzten Griff ins Regal Ihres Buchhändlers möglich gemacht haben, und hoffen an dieser Stelle, dass Ihnen die Lektüre dieses Buchs viel Spaß macht und Ihnen interessante, neue Ansätze für Ihre alltägliche Arbeit bieten kann. Feedback Kein Prozess kann sich ohne Feedback sinnvoll verbessern! Beachten Sie diesen schlauen Spruch bitte nicht nur in Ihrem Arbeitsalltag, sondern schicken Sie uns gerne Ihr Feedback zu diesem Buch an jaxbtransparent2@rmiregistry.de. Vielen Dank! XIII
    • 1 JAXB im Überblick Im folgenden Kapitel werden wir die Java Architecture for XML Binding 2.0 aus der Vo- gelperspektive betrachten. Hier gilt es, die wesentlichen Teile der JAXB-Spezifikation an- schaulich und im Überblick darzustellen. Insbesondere werden wir hier die Begriffe prä- gen, mit denen wir die Komponenten der JAXB im weiteren Verlauf des Buches und der Tutorials referenzieren werden. Wir werden darauf eingehen, welche Ziele mit der JAXB- Spezifikation 2.0 insgesamt angestrebt wurden. Um die Hintergründe der JAXB zu verstehen, darf ein Blick auf die Entstehung der JAXB- Spezifikation nicht fehlen. Mit diesem Grundverständnis über den Aufbau und das Zu- sammenspiel der einzelnen Architekturkomponenten gerüstet, wird es uns leichter fallen, die später im Programmiertutorial vorgestellten Funktionen zu verstehen. Für Anwender, die bereits mit der Version 1.0 der JAXB gearbeitet haben, werden wir abschließend die Unterschiede und Neuerungen in der Version 2.0 vorstellen. 1.1 Ziele Eine High-Level-XML-API bieten Die Java Architecture for XML Binding ermöglicht dem Applikationsentwickler, seine Ja- va-Anwendung optimal mit XML interagieren zu lassen. JAXB hat dabei den Anspruch, eine API auf weit abstrakterer Ebene zu bieten, als das bisher mit parser-basierten Ansät- zen wie SAX und DOM möglich war. Auch Entwickler, die nicht mit diesen Parsern ver- traut sind, sollen die Möglichkeit haben, XML in ihre Anwendungen zu integrieren. Die JAXB-Spezifikation bemüht sich daher um eine möglichst einfache, für Java- Entwickler intuitiv nutzbare Schnittstelle für den Zugriff auf XML-Daten. Doch was eignet sich als intuitive Schnittstelle? Java Beans sind wohl eines der Konzepte, die jedem Java- Entwickler vertraut sind. Daher liegt es nahe, Bindungsinformation und Daten durch Klas- sen im Java Beans-Stil zu repräsentieren. Und genau das ist das primäre Ziel der JAXB, die Bindung von XML an Java über portable Java Beans, im Fachjargon auch Pojos, kurz 1
    • 1 JAXB im Überblick für plain old Java objects, genannt. Auf diese Weise können wir bequem über die vertrau- ten Java-Programmiermethoden mit schemabasierten XML-Daten arbeiten. Die konsequente Einführung des Pojo-Konzepts in die JAXB-Spezifkation und die einfa- che Konfiguration dieser Objekte mit Annotationen vereinfachen die Erstellung dieses Typs von Datenbindung ungemein. Java 5-Spracherweiterungen nutzen Um diese Bindung bei Bedarf individuell anzupassen, enthält JAXB Konfigurationsme- chanismen, welche die Struktur der erzeugten Klassen bzw. des erzeugten Schemas beein- flussen können. Dafür werden u.a. Java-Annotationen verwendet, die eine der Erweiterungen darstellen, die mit der Java Standard Edition 5 eingeführt wurden. Die JAXB-Spezifikation macht aber auch regen Gebrauch von den weiteren Neuerungen der JSE 5 wie den typsicheren Enumerationen und den sogenannten Generics. Diese Spracherweiterungen machen die generierten Klassen und XML-Schemas einfacher und vor allem auch deren Verwendung sicherer (insbesondere typsicherer). Die Struktur der erzeugten Klassen und XML-Schemas wird durch Standardkonfiguratio- nen der JAXB und benutzerdefinierte Konfigurationen fest vorgegeben. Oft ist es aber auch nötig, die generierten Klassen um benutzerdefinierten Code zu erweitern. Auch hier- für müssen Mechanismen definiert werden, um die generierten Klassen so flexibel wie möglich zu machen. XML-Schema vollständig unterstützen Um die JAXB in realen Anwendungen einsetzbar zu machen, ist außerdem eine vollstän- dige Unterstützung der W3C XML-Schemasprache ein weiteres primäres Ziel der JAXB 2.0. Denn nur durch eine vollständige Unterstützung von XML-Schema wird sich JAXB als Standard durchsetzen können. Bidirektionale Bindung unterstützen Ein weiteres wichtiges Ziel der Spezifikation ist die Unterstützung einer bidirektionalen Datenbindung, d.h., sowohl die Generierung von Java Beans aus einem bestehenden Schema als auch der umgekehrte Weg, die Generierung eines Schemas aus einem beste- henden Java Beans-Datenmodell, soll durch die JAXB 2.0 unterstützt werden. Dabei soll auch ein Round Trip möglich sein. Das bedeutet, dass für den Weg Java–XML– Java, also eine Generierung eines Schemas aus einem Java-Datenmodell und die erneute Ableitung eines Datenmodells aus diesem Schema, Eingabe und Ausgabe äquivalent sind. Unterstützung von Webservices Die Generierung eines Java-Datenmodells aus einem XML-Schema, um eine Anwendung mit XML-Dokumenten interagieren zu lassen, ist sicherlich vielen ein Begriff. Aber auch 2
    • 1.1 Ziele der umgekehrte Weg gewinnt im Zeitalter der Webservices mehr an Bedeutung. Wird eine Anwendung beispielsweise als Webservice veröffentlicht, so wird das existierende Daten- modell der Anwendung durch ein WSDL-Dokument beschrieben. Dies kann durch JAXB 2.0 automatisiert werden, indem aus dem existierenden Datenmodell ein XML-Schema generiert wird, das dann bei der Kommunikation über XML und SOAP verwendet wird. In diesem Zusammenhang sollten wir nicht verschweigen, dass die JAXB 2.0- Spezifikation die Grundlage für die Bindung von WSDL an Java-Datentypen in der Java API für XML Web Services (JAX-WS 2.0) bildet. Damit soll JAXB zum Standard für Da- tenbindungen bei Java-basierten Webservices werden. Validierung jederzeit ermöglichen Auch die Validierung von XML-Dokumenten ist eins der Themen, die durch JAXB adres- siert werden sollen. Sowohl beim Unmarshalling, also der Transformation von XML- Inhalten in Java-Objekte, als auch beim Marshalling, der Transformation von Java- Objekten in XML-Dokumentstrukturen, kann eine Validierung anhand eines XML- Schemas durchgeführt werden. Die Validierung soll dabei so gestaltet sein, dass flexibel auf ungültige Inhalte reagiert werden kann. Um das Rad nicht neu zu erfinden, wird bei der Validierung auf bereits bestehende Technologie anderer Java-Spezifikationen zurückge- griffen. Schemaevolution unterstützen Ein großes Problem bei der Entwicklung von Datenbindungen an XML-Schema ist die Weiterentwicklung des XML-Schemastandards. Ein Ziel der JAXB ist daher die Unter- stützung des Umgangs mit dieser sog. Schemaevolution. Portabilität zwischen JAXB-Implementierungen Um die JAXB als einen De-facto-Standard für XML-Datenbindungen zu etablieren, soll die Spezifikation in die kommende Java-Version 6.0, Codename „Mustang“, einfließen. Daher muss die Portabilität der generierten Klassen auf Quellcode- und Binärcode-Ebene sichergestellt werden. Portabilität bedeutet hier, dass die generierten Klassen einer be- stimmten JAXB-Implementierung von jeder anderen Implementierung genutzt werden können. Portabilität des Quellcodes bedeutet, dass durch JAXB erstellter Quellcode von allen JAXB-Implementierungen verstanden wird. Der erstellte Quellcode darf außerdem keine Abhängigkeiten zu einer bestimmten Implementierung besitzen. Die Portabilität des Binär- codes macht eine erneute Kompilierung dieses Quellcodes bei einem Wechsel der Imple- mentierung überflüssig. Dieser Ansatz unterscheidet sich von bisherigen Frameworks, die sich des Mittels des By- tecode Enhancements bedienen, um eine einfache Javabean nach dem Kompilieren um Framework-spezifische Funktionalitäten zu erweitern. Solchermaßen erweiterter Bytecode ist dann nicht mehr portierbar. 3
    • 1 JAXB im Überblick 1.2 Entstehung Spezifizierung durch JSR 222 JAXB ist aus dem Java Community Process 1 , kurz JCP, hervorgegangen. Im JCP entwi- ckeln Expertengruppen Spezifikationen im Bereich der Java-Entwicklung. Diese Spezifi- kationen werden als Java Specification Requests (JSR) betrieben und veröffentlicht. Einige bekannte JSRs sind etwa die Java 5 Generics aus JSR 14 oder typsichere Enumerationen in JSR 201. Auch für die JAXB gibt es eine Expertengruppe, deren Hauptaufgabe natürlich die Weiter- entwicklung der JAXB-Spezifikation ist. Neben dieser Spezifikation in Papierform besteht ein JSR in der Regel noch aus einer Codebasis, nämlich einer Referenzimplementierung (RI) und einem Technology Compatibility Toolkit (TCK). Die Referenzimplementierung dient dazu, den aktuellen Stand der Spezifikation als Imp- lementierung widerzuspiegeln und zu validieren. Weitere solcher Implementierungen der Spezifikation durch andere Anbieter sind natürlich möglich, sogar erwünscht. So wird mit JAX-Me2 2 eine alternative Implementierung der JAXB von der Apache Group 3 betrieben. Das TCK stellt die Kompatibilität einer JAXB-Implementierung zum JAXB-Standard si- cher. Es besteht aus einer Reihe von Tests, die eine JAXB-Implementierung erfolgreich durchlaufen muss, um sich für den JAXB Standard zu zertifizieren. Entwicklung durch das JAXB Project Die Entwicklung und Verwaltung der Referenzimplementierung wird durch das JAXB Pro- ject betrieben. Das JAXB Project wurde bei Sun als Open-Source-Projekt veröffentlicht. Diese Entwicklergruppe realisiert neben der oben beschriebenen Referenzimplementierung und dem TCK noch weitere Tools zur Unterstützung rund um JAXB. Das JAXB Project ist wiederum Teil des Projekts Glassfish, das eine Referenzimplementierung der neuen Java Enterprise Edition 5 darstellt.Veröffentlichung Erstmals veröffentlicht wurde JAXB in der Version 1.0 durch den JSR 31. Seit dieser Ver- sion ist JAXB auch Bestandteil des Java Web Service Developer Packages (Java WSDP, aktuell in der Version 2.0). In diesem Buch werden wir uns ausschließlich der neuen JAXB in der Version 2.0 widmen, die einige bedeutende Neuerungen umfasst und damit einen großen Schritt in Richtung Projekttauglichkeit macht. Die JAXB 2.0 wurde im April 2006 als Final Release des JSR 222 verabschiedet. Getragen wird die Spezifikation dabei hauptsächlich von Sun Microsystems. Die Expertengruppe 1 http://www.jcp.org 2 http://ws.apache.org/jaxme 3 http://www.apache.org 4 https://jaxb.dev.java.net 4
    • 1.3 Architektur wird jedoch noch von vielen weiteren Industriegrößen wie BEA, Oracle und SAP unter- stützt. Ziel dabei ist, die JAXB-Spezifikation in Zukunft in die Java Standard Edition zu integrieren. Damit wäre JAXB die Standardlösung für Java-XML-Datenbindungen. Doch genug der Geschichte, es ist an der Zeit, einen Blick auf die Architektur von JAXB zu werfen. 1.3 Architektur Als erster Überblick sind hier die einzelnen Komponenten der JAXB-Architektur gelistet. In den folgenden Abschnitten werden wir die genannten Komponenten dann etwas näher beschreiben. Architekturkomponenten Annotationen: Die JAXB ist ein annotationsgetriebenes Framework (annotation driven). Annotationen werden dazu verwendet, die Abbildung von Java- auf XML- Repräsentation zu konfigurieren. Schema-Compiler: Der Schema-Compiler bindet ein existierendes Schema an ein gene- riertes Java-Datenmodell. Diese Erzeugung einer Java-Repräsentation aus einem XML-Schemadokument ist ein häufig verwendeter Weg, die Java- und XML-Welten zu verbinden. Er eignet sich besonders für dokumentgetriebene Anwendungsszenarien. Schema-Generator: Der Schema-Generator bindet ein existierendes Java-Datenmodell an ein generiertes XML-Schema. Die Information für die Abbildung der Java- Elemente auf ein XML-Schema definiert der Entwickler durch Annotationen im exis- tierenden Datenmodell. Dieser Weg eignet sich am besten für modellgetriebene An- wendungsszenarien. Binding Framework: Das Binding Framework stellt die Schnittstelle zur Anwendung dar. Es bietet eine Reihe von API-Klassen und -Funktionen, die zur Laufzeit aufgeru- fen werden: Die wichtigsten Funktionen sind das Marshalling und Unmarshalling. Das Unmarshalling realisiert die Transformation von XML zu Java. Das Marshalling hin- gegen überführt Java-Objekte in XML-Dokumentinstanzen. Begleitend zu diesen Ope- rationen kann automatisch eine Validierung der XML-Inhalte anhand eines XML- Schemas erfolgen. Mit dem Binder schließlich kann eine transparente Bearbeitung ei- nes XML-Dokuments über ein gebundenes Java-Datenmodell erfolgen – Marshalling und Unmarshalling finden hier im Hintergrund statt. 5
    • 1 JAXB im Überblick Compile-Zeit- vs. Laufzeitkomponenten Grundsätzlich können wir die Architekturkomponenten in zwei Bereiche aufteilen: Komponenten der Compile-Zeit: Schema-Compiler und Schema-Generator werden zu- sammen mit den Annotationen zur Compile-Zeit, d.h. vor Ausführung der Anwendung, benötigt. Sie stellen die Bindung durch Generieren eines Java-Datenmodells bzw. eines Schemas her. Komponenten der Laufzeit: Das Binding Framework wird zur Laufzeit von der An- wendung selbst benutzt, um XML-Inhalte zu verarbeiten. Das Zusammenspiel dieser Komponenten zeigt die folgende Architekturübersicht. XML-Schema Bindungsdeklarationen Portable Java Beans JAXB-Annotationen JAXB Annotationen Compile-Zeitkomponenten Laufzeitkomponenten <f:foo ... <element ... Unmarshalling Binding-Framework Unmarshalling </element> </f:foo> JAXB API Marshalling Marshalling Validierung XML-Dokument Java Beans-Instanzen Abbildung 1.1 Komponenten der JAXB-Architektur 6
    • 1.3 Architektur 1.3.1 Annotationen Annotationen werden, wie bereits erwähnt, durchgängig durch die JAXB verwendet, so- wohl vom Schema-Compiler als auch vom Entwickler selbst. Sie werden sowohl in den generierten Java Beans-Klassen verwendet als auch im XML-Schema. Wir unterscheiden daher zwei Arten von Annotationen: Mapping-Annotationen: Bei der Generierung eines Java-Datenmodells aus einem exis- tierenden XML-Schema versieht eine JAXB-Implementierung die generierten Klassen mit Java-Annotationen, die Informationen über die Java-XML-Bindung enthalten. Ja- va-Annotationen sind im JSR 175 5 beschrieben und eine der Spracherweiterungen der Java Standard Edition 5. Diese Mapping-Annotationen beschreiben in JAXB die Ab- bildung der XML-Elemente des Schemas auf die Elemente des generierten Java- Datenmodells (z.B. Klassen, Eigenschaften etc.). Dadurch beinhaltet das generierte Da- tenmodell neben den Java-Klassen gleichzeitig eine Repräsentation des zugrunde lie- genden Schemas. Das XML-Schema selbst wird daher zur Laufzeit nicht mehr gebraucht, da alle benö- tigten Informationen bereits in den Annotationen gespeichert werden. Der eigentliche Vorteil der Annotationen zeigt sich jedoch erst im umgekehrten Fall, der Bindung von XML-Daten an ein existierendes Java-Datenmodell. Hier kann der Entwickler jetzt selbst seine existierenden Java-Klassen mit Mapping-Annotationen versehen. Diese Mapping-Annotationen definieren die Bindung der Java-Klassen an die XML-Daten. Sie stellen dann implizit ein XML-Schema dar. Werden keine Mapping-Annotationen vom Entwickler angegeben, greift JAXB auf Defaultkonfigurationen zurück. Die Refe- renz enthält in Kapitel 7.5 eine detaillierte Auflistung aller möglichen Mapping- Annotationen und ihre Auswirkung auf den erzeugten Code. Bindungskonfigurationen: Auch bei der Erzeugung eines Datenmodells aus einem exis- tierenden XML-Schema kann die Bindung individuell konfiguriert werden. Dazu kann der Entwickler Annotationen für das XML-Schema angeben. Diese Annotationen wer- den Bindungsdeklarationen genannt und sind selbst wieder in XML formuliert. Da- durch kann z.B. definiert werden, dass alle generierten Java-Klassen für ein XML- Schema das Interface  implementieren. Bindungskonfigurationen kön- nen definiert werden, indem ein existierendes XML-Schemadokument mit Annotatio- nen versehen wird. Diese Annotationen werden dann nicht über Java-Annotationen, sondern direkt in XML durch das -Element formuliert. Sie können entwe- der im Schema selbst oder über eine externe XML-Datei übergeben werden. Wir sehen also, dass Annotationen ein grundlegendes Konzept der JAXB sind. Sie tragen zur Konfigurierbarkeit und Portabilität der Java-XML-Bindung bei. 5 http://www.jcp.org/en/jsr/detail?id=175 7
    • 1 JAXB im Überblick 1.3.2 Der Schema-Compiler Um eine Bindung von XML-Schema nach Java zu erstellen, generiert der Schema- Compiler portable Java-Objekte aus einem bestehenden Schema. <xs:schema ... <xs:element ... <xs:attribute ...> <xs:annotation> ... </xs:annotation> </xs:schema> @XmlRootElement public class { XML-Schema @XmlElement ... Schema-Compiler String element ... @XmlAttribute <jaxb:bindings ... <jaxb:class... Java Beans mit <jaxb:property ...> JAXB-Annotationen </jaxb:bindings> Bindungs- konfiguration Abbildung 1.2 Der Schema-Compiler Woher weiß der Schema-Compiler nun, wie das generierte Java-Datenmodell aussehen soll? Die JAXB-Spezifikation definiert dazu für jede Komponente der W3C XML- Schemasprache eine entsprechende Java-Repräsentation, z.B. eine Java-Klasse, eine Ei- genschaft oder eine Enumeration. Jedem dieser Java-Sprachelemente werden zusätzlich Mapping-Annotationen hinzugefügt, welche die entsprechende Schemakomponente beschreiben. Diese Abbildung zwischen XML-Schema und Java stellt die Standardbindung des Schema-Compilers dar. In den meisten Fällen genügt diese Standardbindung den Anforderungen einer Applikatio- nen. In manchen Fällen sind allerdings Anpassungen der generierten Java-Klassen nötig. Hier kommen die im vorigen Abschnitt erwähnten Bindungsdeklarationen zum Einsatz. Sie überschreiben die Standardbindung des Schema-Compilers und erlauben benutzerdefi- nierte Abbildungen von Schemakomponenten auf Java. Formuliert werden diese Bin- dungsdeklarationen ebenfalls in XML. Auf die einzelnen Konfigurationsmöglichkeiten ge- hen wir im Rahmen des Programmiertutorials genau ein. Die folgende Tabelle gibt uns einen Überblick über die Abbildung der Schemakomponen- ten auf Java-Programmelemente. 8
    • 1.3 Architektur Tabelle 1.1 Abbildungsbeziehungen zwischen XML-Schema und Java-Elementen XML-Schemakomponente Java-Komponente Namespace Java-Paket   Komplexer Datentyp Benutzerdefinierte Java-Klasse       Einfacher Datentyp Java-Datentypen und Wrapper-Klassen    Einfacher Datentyp mit Enumeration Facet Java-Enumeration                 Unterelemente eines komplexen XML-Typ Java-Eigenschaften der gebundenen Klasse       Das bedeutet, dass wir nach dem Ausführen des Schema-Compilers eine Ansammlung von Java-Klassen bekommen, die der Schema-Compiler in dem angegebenen Paket ablegt. Der Schema-Compiler erzeugt zusätzlich dazu noch eine Klasse . Mit dieser Klasse wird dem Programmierer, der Name verrät es bereits, eine Factory-Klasse an die Hand gegeben. Mit dieser Klasse können nun bequem Instanzen der generierten JAXB Klassen erzeugt werden. Wir werden uns die  im Zusammenhang mit dem Marshalling von XML-Dokumenten noch genauer ansehen. 1.3.3 Der Schema-Generator Der Schema-Generator verwendet die in Tabelle 1.1 definierten Abbildungsregeln im um- gekehrten Sinne, um ein Schema aus einem bestehenden Java-Datenmodell zu erzeugen. 9
    • 1 JAXB im Überblick <f:foo ... <element ... </element> </f:foo> @XmlRootElement public class ... { XML-Dokument @XmlElement ... String element ... <xs:schema ... @XmlAttribute <xs:element ... <xs:attribute ...> Java Beans mit <xs:annotation> JAXB-Annotationen ... </xs:annotation> </xs:schema> XML-Schema Abbildung 1.3 Der Schema-Generator Auch híer gibt es Standardbindungen, die z.B. aus einer benutzerdefinierten Klasse einen komplexen Typen im XML-Schema erzeugen. Für die Default-Bindungen müssen keine expliziten Annotationen im Datenmodell angegeben werden, die JAXB-Spezifikation setzt in diesem Fall die Standardbindung voraus. Ein Java-Datenmodell kann auf diese Weise mit der Angabe von nur einigen wenigen An- notationen vollständig auf ein Schema abgebildet werden. Die Standardbindungen können aber durch die Angabe der oben erwähnten Mapping-Annotationen ergänzt bzw. über- schrieben werden, um die Bindung entsprechend anzupassen. Der Vorteil ist, dass diese Annotationen direkt in ein existierendes Datenmodell eingefügt werden können. Wann und wie wir ein Datenmodell mit Mapping-Annotationen versehen, wird ausführlich im Programmiertutorial behandelt. Eine detaillierte Auflistung der mögli- chen Annotationen findet sich in der Referenz. 1.3.4 Das Binding Framework Wie bereits erwähnt, vereint das Binding Framework die API-Funktionen der JAXB zur Verarbeitung von XML-Dokumenten zur Laufzeit. Es befindet sich im Paket   der JAXB-Laufzeitbibliothek. Es bietet die folgenden Funktionalitäten, die wir in diesem Abschnitt im Detail darstellen: Umarshalling: Laden von XML. Marshalling: Speichern von XML. 10
    • 1.3 Architektur Event-Callbacks: Nachrichten im Rahmen des Unmarshallings bzw. Marshallings ver- arbeiten. Validierung: Die Gültigkeit von verarbeiteten XML-Dokumenten sicherstellen. Binder: Modifizieren eines XML-Dokuments ohne explizites Laden oder Speichern. 1.3.4.1 Unmarshalling Beim Unmarshalling wird eine XML-Schemainstanz, d.h. ein XML-Dokument, das ein gegebenes Schema als Formatbeschreibung referenziert, in einen Graph aus Java-Objekten transformiert. Dieser Objektgraph besteht aus Instanzen von Java Beans, die mit Mapping- Annotationen versehen sind. Der Inhalt unseres XML-Dokuments ist somit nach erfolgtem Unmarshalling im Speicher präsent. Unsere Anwendung kann dann ohne den Einsatz einer zusätzlichen XML-API auf die Java Beans wie auf normale Objekte zugreifen. Klingt einfach, oder? Ist es auch, wie wir später im Programmiertutorial sehen werden. Ein häufiges Problem, auf das wir beim Unmarshalling stoßen, sind ungültige XML- Inhalte. Es ist zwar möglich, bereits vorher über die Validierung Dokumente mit ungülti- gen Inhalten auszuschließen. Aber nicht immer wollen wir uns den Overhead einer Vali- dierung leisten. Oft besitzen die XML-Dokumente auch keine besonders hohe Datenquali- tät, sie sind z.B. unvollständig oder fehlerhaft ausgefüllt. Trotzdem muss die Anwendung mit diesen Inhalten umgehen können. Daher wurde in JAXB 2.0 die Möglichkeit vorgese- hen, ein Unmarshalling von ungültigen Inhalten vorzunehmen. Generell existieren nämlich zwei unterschiedliche Verfahren des Unmarshallings. Structural Unmarshalling: Dieses Verfahren implementiert das strikte Unmarshalling eines XML-Dokuments. Die Reihenfolge der Elemente im XML-Dokument muss ex- akt übereinstimmen mit der im XML-Schema definierten Reihenfolge. Trifft dies nicht zu, wird das Unmarshalling mit einer Fehlermeldung abgebrochen. Das Unmarshalling basiert also auf der Struktur des XML-Dokuments. Eventuelle Abweichungen vom zugrunde liegenden Schemadokument werden sofort aufgedeckt. Dieser Ansatz wurde in früheren Versionen der JAXB verfolgt. Er eignet sich nicht besonders für die Be- handlung von ungültigen oder veränderten Inhalten. Flexible Unmarshalling: Dieses Verfahren ist weniger strikt und lässt uns auch Doku- mente verarbeiten, deren Elementreihenfolge nicht hundertprozentig mit dem Schema übereinstimmt. Die Elemente werden dem Namen nach transformiert statt nach ihrer Position im Dokument. Dadurch können Dokumente verarbeitet werden, die zwar vom Schema abweichen, deren Inhalte aber dennoch ausreichende Information besitzen. Dies gilt z.B. für XML-Dokumente mit abweichender Elementreihenfolge, fehlenden oder unbekannten Elementen. JAXB 2.0 verfolgt standardmäßig ein flexibles Unmars- halling, um beispielsweise die Evolution, also die Weiterentwicklung von XML- Schemas und XML-Dokumenten zu unterstützen. Denn immer häufiger unterliegen XML-Dokumente einer ständigen Weiterentwicklung, so dass der Bedarf für ein fehler- 11
    • 1 JAXB im Überblick tolerantes, flexibles Unmarshalling ständig größer wird. Ein konkretes Beispiel hierzu findet sich im Unmarshalling-Abschnitt des Tutorials. 1.3.4.2 Marshalling Das Marshalling geht nun den umgekehrten Weg. Ein im Speicher vorhandener Objekt- graph wird serialisiert, d.h., in ein XML-Dokument überführt. Der Objektgraph besteht dabei wieder aus Instanzen von Java Beans, die mit JAXB-spezifischen Annotationen ver- sehen sind. Durch diese Annotationen werden die Objekte auf die zugehörigen XML-Elemente abge- bildet. Die Zielstruktur, in die Objekte überführt werden, kann dabei verschiedene Formate besitzen. So kann eine JAXB-Implementierung das XML in Standardausgabeströme der Java Core API wie  oder  schreiben, aber auch höhere Ausgabeschnittstellen und Standards wie SAX, DOM, StAX nutzen und sogar mit Transformationen per XSL kombinieren. 1.3.4.3 Event Callbacks Sowohl für das Marshalling als auch das Unmarshalling kann der Entwickler sog. Call- back-Methoden einfügen. Diese Methoden arbeiten nach dem Hollywood-Prinzip („don’t call us we’ll call you“), das u.a. durch das Spring Framework 6 populär geworden ist. Da- durch kann während des Marshallings/Unmarshallings applikationsspezifische Logik aus- geführt werden. Mit der Implementierung dieser Callback-Mechanismen werden wir uns später im Programmiertutorial noch näher beschäftigen. 1.3.4.4 Validierung Eine Validierung von Inhalten kann eine JAXB-Implementierung automatisch sowohl beim Unmarshalling als auch beim Marshalling durchführen. Diese Validierung ist jedoch bewusst optional gehalten, um Anwendungsszenarien behandeln zu können, die keine Va- lidierung benötigen oder wo eine Validierung der Daten nicht regelmäßig möglich ist. Beim Unmarshalling wird das zu verarbeitende XML-Dokument überprüft. Beim Marshal- ling dagegen muss der im Speicher existierende Objektgraph auf Gültigkeit überprüft wer- den. Wer jetzt denkt, die Validierung beim Unmarshalling sollte doch auch genügen, der sollte sich das Fail-fast-Prinzip ins Gedächtnis rufen. Nach diesem Entwurfsprinzip für Pro- grammierschnittstellen sollten Fehler so früh wie möglich aufgedeckt und an die Anwen- dung kommuniziert werden. Diesem Prinzip folgt auch die JAXB. Das bedeutet, dass un- gültige Daten bereits beim Marshalling aufgedeckt werden sollten, also noch bevor die Da- ten eventuell an eine andere Komponente einer Architektur weitergegeben werden. 6 http://www.springframework.org 12
    • 1.3 Architektur Denkbar wäre z.B. eine Anfrage an einen Webservice, bei der XML-Daten einem WSDL- Dokument gemäß versendet werden. Eine Validierung der Daten vor der Absendung der Anfrage, beim Marshalling, hilft, Fehler dort aufzudecken, wo sie entstehen. Die Validierung führt also die Überprüfung der im XML-Schema definierten Einschrän- kungen und Formatvorgaben durch. Dabei können die Einschränkungen in zwei Katego- rien unterteilt werden. Statische Einschränkungen: Dies sind z.B. Einschränkungen auf Datentypen wie ,  oder . Solche Einschränkungen werden später durch die por- tablen Java Beans aufrechterhalten. Verletzungen dieser Einschränkungen werden be- reits durch die Java-Typüberprüfung erkannt und können zur Laufzeit bei der Um- wandlung von und in XML theoretisch nie auftreten. Dynamische Einschränkungen: Einschränkungen auf Wertebereiche oder die Definition von komplexen Typen mit bestimmten Kindelementen können erst zur Laufzeit über- prüft werden. Diese Validierungen können durchaus sehr aufwendig werden, da unter Umständen der gesamte Objektgraph überprüft werden muss, z.B. um die Eindeutigkeit einer XML-Element-ID zu überprüfen. Tritt nun ein Verstoß gegen eine der oben genannten Einschränkungen auf, so wird ein Fehlerereignis generiert. Das Fehlerereignis besitzt Informationen zu der Art des Fehlers und dem Ort, an dem der Fehler aufgetreten ist. Solche Fehlerereignisse können entweder sofort an die aufrufende Anwendung weitergegeben oder zunächst gesammelt und nach erfolgter Validierung als Liste weitergereicht werden. Zur Durchführung der Validierung muss im einfachen Fall ein XML-Schema angegeben werden. Die eigentliche Validierung wird dabei seit JAXB 2.0 durch die in der Java Stan- dard Edition 5 enthaltene JAXP 1.3 API übernommen. JAXP 1.3 definiert eine Standard- API zur Validierung von XML-Dokumentinstanzen. Dieses „Outsourcing“ der Validie- rung hat den zusätzlichen Vorteil einer kompakteren Implementierung. Die Verwendung der JAXP Validation API bietet weit mehr Flexibilität und Konfigurier- barkeit als die JAXB-eigene Validierung der Version 1.0. So können beispielsweise neben den Standardmechanismen zur Behandlung der Validierung auch eigene Implementierun- gen der sog. Validation-Event-Handler-Interfaces verwendet werden. Dadurch kann indi- viduell auf ganz bestimmte Fehler reagiert werden, z.B. um eine gewisse Fehlertoleranz einer Anwendung zu gewährleisten. Die Validierung ist dabei nicht auf XML-Schema festgelegt – so können über entspre- chende Schnittstellen auch ganz eigene Implementierungen für eine XML-Validierung beigesteuert werden. 1.3.4.5 Binder Die -Komponente der JAXB-API kann zwei verschiedene Sichten auf ein XML- Dokument gleichzeitig verwalten. Angenommen, es existiert in einer Anwendung bereits 13
    • 1 JAXB im Überblick eine Sicht auf ein XML-Dokument, z.B. als DOM 7 . Ein DOM-Modell repräsentiert ein XML-Dokument durch Objekte, die Knoten, Elemente und Attribute darstellen. Mithilfe des Binders kann zusätzlich dazu für das gesamte Dokument oder auch nur für Teile eine zweite Sicht erstellt werden. Diese Sicht besteht aus den bereits bekannten JAXB-Klassen. Wird nun von der Anwendung eine dieser beiden Sichten verändert, kann der Binder die jeweils andere Sicht mit den Änderungen aktualisieren und so beide Sichten synchron hal- ten. Ein häufiger Anwendungsfall ist hier die Darstellung eines Ausschnitts aus dem XML- Dokument durch JAXB-Klassen. Diese JAXB-Klassen stellen die zu verändernden Teile des Dokuments dar. Das gesamte Dokument ist weiterhin als DOM-Modell verfügbar, wird aber vielleicht nur lesend verwendet. Schreibzugriffe erfolgen aufgrund der einfache- ren Verwendbarkeit durch JAXB. Der modifizierbare Ausschnitt des Dokuments kann dabei z.B. durch einen XPath- Ausdruck dargestellt werden. Die folgende Abbildung soll die Funktion der - Komponente etwas veranschaulichen. unmarshal Binder update customer <response ... <customer ... load <address .../> </customer> JAXB </response> save Mapping <customer> address XML-Dokument DOM-Baum Java Beans-Instanzen Abbildung 1.4 Die Binder-Komponente 1.4 1.0 + 1.0 = 2.0? Die Neuerungen der JAXB 2.0 Was hat sich nun seit der Version 1.0 bei der JAXB-Spezifikation getan? Lohnt es sich, meine Anwendung zu migrieren? Ist JAXB noch komplizierter geworden als in der Vor- gängerversion? Diese Fragen werden sich diejenigen stellen, die bereits mit JAXB in Be- rührung gekommen sind. 7 Document Object Model 8 http://www.w3.org/TR/1999/RECxpath-19991116 14
    • 1.4 1.0 + 1.0 = 2.0? Java nach XML-Schemaabbildung Die JAXB hat sich mit der Version 2.0 fundamental verändert. Die größte Änderung dürfte die Einführung der Bindung existierender Java-Datenmodelle an XML sein. Während in JAXB 1.0 im Wesentlichen ein XML-Schema in ein Java-Datenmodell umgewandelt wur- de, ist jetzt eine elegante Art der Datenbindung durch die Annotation von existierenden Klassen entstanden. In JAXB 2.0 kann eine Java-XML-Bindung konfiguriert werden, ohne dass hierbei aus ei- nem XML-Schema mithilfe des Schema-Compilers JAXB-spezifische Klassen generiert werden müssen. Die aus Sicht der Datenbindung bestehende Einbahnstraße in JAXB 1.0 wurde sozusagen zu einer bidirektionalen Autobahn in JAXB 2.0 ausgebaut. Portabilität JAXB geht außerdem in der Version 2.0 einen fundamentalen Schritt weiter in Richtung Portabilität. In JAXB 1.0 werden aus den Komponenten eines Schemas Interfaces und de- ren Implementierungsklassen generiert. Diese vom Schema abgeleiteten Klassen gingen eine enge Kopplung mit der jeweiligen Implementierung der JAXB und mit der JAXB- Laufzeitbibliothek selbst ein. Für die Abwärtskompatibilität werden diese Interfaces zwar weiterhin unterstützt, jedoch geht man offiziell einen anderen Weg. In JAXB 2.0 sind es die mit Annotationen versehe- nen portablen Klassen, die an Schemakomponenten gebunden werden. Da diese Klassen im Wesentlichen Java Beans darstellen, sind sie an keine spezifische Implementierung der JAXB gebunden. Als Entwickler arbeitet man daher mit konkreten Klassen statt der bisherigen Interfaces. Es ist möglich, ein Java-Datenmodell nachträglich und ohne wesentliche Änderung von einer JAXB-Implementierung auf eine andere zu portieren, aber auch von einer XML- Datenbindung beispielsweise an eine Datenbank-Datenbindung. Volle Unterstützung von XML-Schema Ein weiteres Manko der JAXB 1.0 ist die unvollständige Unterstützung der XML- Schemasprache. Mit der Version 2.0 ist in JAXB die volle Unterstützung der W3C XML- Schemaspezifikation angestrebt. Es können jetzt alle in W3C XML-Schema vorhandenen Konzepte in einem Java-Datenmodell abgebildet werden. Hinzugefügt wurde unter ande- rem die fehlende Unterstützung von Wildcards und Typsubstitutionen. Java 5-Unterstützung Dem allgemeinen Trend folgend, setzt auch JAXB 2.0 voll auf die Spracherweiterungen der Java Standard Edition 5. Zum einen sind das die erwähnten Annotationen. Aber auch Generics werden unterstützt, was eine erhöhte Typsicherheit zur Folge hat, da z.B. alle ge- nerierten Listen bereits den korrekten Typ besitzen. Auf der anderen Seite bedeutet dies 15
    • 1 JAXB im Überblick aber auch, dass Anwendungen mit JAXB 2.0 die Verwendung der JSE 5 oder höher vor- aussetzen. Redesign der Validierung Auch was die Validierung angeht bietet JAXB 2.0 einige Neuerungen. Um eine flexiblere Behandlung der Validierung von XML-Dokumenten zu ermöglichen, wird in der Version 2.0 die Validierungskomponente der JAXP 1.3 API verwendet. Damit wurde die bisherige On-Demand-Validierung beim Unmarshalling ersetzt. Die Validierung kann nun optional sowohl beim Unmarshalling als auch beim Marshalling durchgeführt werden. Die neue Validierungskomponente ist wesentlich flexibler und er- laubt nun auch das Unmarshalling von teilweise ungültigen XML-Dokumenten. Dadurch wurden auch Performance-Aspekte in JAXB 2.0 adressiert. So konnte die Anzahl der generierten Klassen gesenkt und die Größe der Laufzeitbibliotheken verringert werden. Umstieg von JAXB 1.0 nach 2.0 Doch was passiert nun mit Applikationen, die auf der Version 1.0 der JAXB basieren? JAXB 2.0 beinhaltet alle nötigen Bibliotheken, die für die Ausführung von existierenden JAXB 1.0-Applikationen benötigt werden. Der Schema-Compiler  der Version 2.0 ist auch in der Lage, JAXB 1.0-kompatiblen Code zu generieren. Um eine auf der JAXB 1.0 basierende Applikation auf die JAXB 2.0 zu portieren, muss allerdings das Schema mit der neuen Version des  Schema-Compilers kompiliert und die Anwendung mit den generierten Klassen aktualisiert werden. Außerdem muss natürlich beachtet werden, dass JAXB 2.0 nur ab der Java-Version 5 eingesetzt werden kann. Wobei im Rahmen der Spezifikation darauf geachtet wurde, dass eine JAXB-Implementierung potenziell über entsprechende „Retro-Translatoren“ zumindest zur Laufzeit Java 1.4- Kompatibilität bieten können. 16
    • 2 Basistechnologien In diesem Kapitel gehen wir auf die im Rahmen der JAXB verwendeten Basistechnologien XML-Schema, XPath und ANT ein. 2.1 XML-Schema XML ist seit langem eins der Standardformate, wenn es um die plattformunabhängige Repräsentation von Daten geht. Das Besondere an XML: Es werden nicht nur die reinen Daten, sondern auch die Metadaten in einem XML-Format gespeichert. Also nicht nur die Information „Müller“, sondern auch die Information „Müller ist der Nachname eines Kun- den“. Rein technisch betrachtet ist XML ein sehr redundantes und aufgeblähtes Format, als Datenaustauschformat hat es den großen Vorteil, dass jeder Entwickler ein XML- Dokument öffnen und lesen kann, ohne dass die Daten zusätzlich aufbereitet werden müss- ten. Besonders vielseitig wird XML durch die Möglichkeit, die erwarteten Daten in Form einer DTD oder eines XML-Schemas zu spezifizieren. Über solche Formatbeschreibungen las- sen sich Form und Gültigkeit eines Datensatzes beschreiben: „Jeder Kundendatensatz muss einen Namen angeben, eine Adressangabe ist optional möglich.“ In diesem Kapitel möchten wir auf die wesentlichen Möglichkeiten von XML-Schema eingehen, das sich zu dem umfangreichsten und genauesten Format zur Beschreibung von Formaten gemausert hat. Mit XML-Schema können wir Grammatiken definieren, also Einschränkungen und Regeln zu den Daten in einem XML-Dokument. Ein mit XML-Schema beschriebenes Dokument kann anhand der Grammatik auf seine Gültigkeit überprüft werden. Eine solche Validie- rung wird von einem Schema-Validierer durchgeführt. So lassen sich z.B. Daten beschreiben, die dem Nachrichtenaustausch zwischen verschie- denen Anwendungen dienen. Durch Verwendung eines XML-Schemas wird den einzelnen Komponenten ein einheitliches, überprüfbares Format bereitgestellt. 17
    • 2 Basistechnologien Im Zusammenhang mit XML-Schema werden oft die Begriffe Schemadokument und Schemainstanz verwendet. Ein XML-Schemadokument definiert die oben genannte Grammatik zu den XML- Daten und legt so deren Struktur für alle Beteiligten fest. Eine XML-Schemainstanz hingegen ist ein XML-Dokument, das ein Schemadokument verwendet, um XML-Daten konform zu einer Grammatik zu beschreiben. XML-Schema wird heute von vielen XML-basierten Standards und APIs verwendet wie z.B. der Web Service Description Language (WSDL). Ursprünglich vorgeschlagen von Microsoft, wurde die Sprache schließlich 2001 als Emp- fehlung durch das Webkonsortium W3C 1 offiziell veröffentlicht. Im Gegensatz zu anderen Grammatikdefinitionen wie DTD , die mittels einer zusätzlichen Sprache definiert werden, basiert XML-Schema selbst auch auf XML. Weitere Vorzüge sind die Erweiterbarkeit und eine Vielzahl an vordefinierten Datentypen. Außerdem wer- den objektorientierte Konzepte wie Namensräume und Vererbung unterstützt. Aus diesen Gründen hat sich XML-Schema mittlerweile gegen DTD durchgesetzt. Aber auch XML- Schema hat natürlich Konkurrenz, der wichtigste Standard ist hier wohl RelaxNG, für den in JAXB bereits experimentelle Unterstützung zu finden ist. Bei der Arbeit mit JAXB wird uns XML-Schema ein ständiger Begleiter sein. Es gibt eine ganze Reihe toller Bücher zum Thema XML-Schema. Daher wird dieses Kapitel sich dar- auf beschränken, einen Überblick über die wichtigsten Konzepte zu geben, die wir für das unmittelbare Verständnis der Beispiele in diesem Buch für notwendig halten. Um ein XML-Schema definieren zu können, benötigen wir natürlich ein Grundverständnis für den Aufbau eines XML-Schemas. Daher wird zunächst der Schemaaufbau unter Ver- wendung von Namensräumen erläutert. Danach werden wir uns ausführlich der Definition von Datentypen widmen, da wir diese später mit JAXB an unsere Java-Klassen binden wollen. Ein weiteres wichtiges Thema in diesem Zusammenhang ist die Formulierung von Einschränkungen auf diesen Datentypen. Da wir natürlich mit objektorientierten Datenmodellen arbeiten wollen, darf auch die Ver- erbung von Datentypen in XML-Schema nicht fehlen. Vererbung ist aber nur ein Mittel zur Erweiterbarkeit von Schemas. Wir werden uns daher noch mit weiteren Mitteln zur Definition von erweiterbaren, offenen Schemas befassen. In dieser Hinsicht betrachten wir abschließend das Zusammensetzen eines Schemas aus mehreren Teilschemas, was uns ei- ne komponentenbasierte Definition der Daten ermöglicht. Die genannten Konzepte werden wir anhand eines Objektmodells darstellen, das sukzessi- ve im Verlauf des Kapitels aufgebaut wird. Auf diesem Domänenobjektmodell, im Engli- schen das Domain Object Model, werden dann alle weiteren Programmierbeispiele im Ver- lauf des Buches aufbauen. 1 http://www.w3.org 2 Document Type Definitions 18
    • 2.1 XML-Schema Da eine erschöpfende Behandlung von XML-Schema weit über den Rahmen dieses Kapi- tels hinausgeht, sei für weitere Informationen auf das Buch XML Schema von Eric van der Vlist verwiesen. Ein XML-Schemadokument bildet also die Grundlage einer Java-XML-Bindung mit JAXB. Ein solches Schemadokument beschreibt dabei sowohl Struktur als auch Datenty- pen einer Schemainstanz. Im einfachsten Fall besteht ein Schemadokument aus der Defini- tion der gültigen Elemente sowie deren Reihenfolge und Anordnung. Es lassen sich aber auch komplexe Strukturen aufbauen, die sich über mehrere Schemas erstrecken und ganze Datentyphierarchien aufbauen. Im Verlauf dieses Kapitels werden wir mehrere Schemas entwickeln und diese zu einer komplexen Struktur zusammenfügen. Zunächst aber konzentrieren wir uns auf ein einfaches Beispiel: Stellen wir uns einen Online-Banking-Service vor, der auf eintreffende XML-Requests von Clients eine entsprechende Response im XML-Format zurückliefert. Im Request wird eine Kunden-ID mitgeliefert. Als Antwort liefert der Service dann entsprechende Informationen über die Stammdaten, die Kontodaten sowie über ein evtl. vorhandenes Aktienportfolio des Kunden. Diese Daten werden z.B. aus einer Datenbank gewonnen. Die Struktur der vom Service zurückgelieferten Daten wird durch die folgenden XML-Schemas definiert. response: Enthält die Antwort des Service auf einen eingehenden Request. customerElement: Enthält die Stammdaten eines Kunden. accountElement: Enthält alle kontorelevanten Daten eines Kunden. portfolioElement: Repräsentiert das Aktienportfolio eines Kunden. Das Schema  nutzt dabei die in den Schemas ,  und   erstellten Datentypen, um eine Datenstruktur für die Ausgabe an den Client zusam- menzustellen. Abbildung 2.1 Das response-Schema Um nicht gleich die Übersicht zu verlieren, sehen wir uns zunächst nur die Stammdaten eines Kunden an. 19
    • 2 Basistechnologien Abbildung 2.2 Stammdaten eines Kunden Für diese Daten sieht ein einfaches Schemadokument nun so aus:                Das Dokument oben legt für den Kunden also ein Element mit den entsprechenden Unter- elementen für die Stammdaten an. Das schema-Element Sehen wir uns zunächst den Kopf dieses Dokuments ein wenig genauer an. Ein Schemado- kument beginnt immer mit dem einleitenden Wurzelelement . Im obigen Beispiel sind in diesem -Element zwei weitere Attribute definiert, die beide jeweils eine URL als Wert enthalten.      20
    • 2.1 XML-Schema Diese Attribute definieren verschiedene Namensräume in unserem Schemadokument. Die- se werden gewöhnlich im einleitenden -Element definiert. Ihre Verwendung wird im nächsten Abschnitt behandelt. Sehen wir uns zunächst noch der Vollständigkeit halber ein entsprechendes XML-Dokument zu unserem Schemadokument an.         Dieses Dokument nutzt also das vorher definierte -Element, um einen Kundendatensatz zu beschreiben. 2.1.1 Namespaces verwenden In der Einleitung wurde erwähnt, dass durch XML-Schema Grammatiken definiert werden. Eine Grammatik setzt grundsätzlich auf einem bestimmten Vokabular auf. Solche Vokabu- lare können wir in XML-Schema durch Definition von Elementen frei bestimmen. Was aber, wenn sich unsere Datentypen mit den Definitionen anderer Vokabulare überschnei- den? Das Problem solcher Namenskonflikte wird in XML-Schema durch die Verwendung von Namensräumen, den Namespaces, gelöst. Die XML-Spezifikation definiert einen Na- mespace wie folgt: An XML namespace is a collection of names, identified by a URI reference [RFC2396], which are used in XML documents as element types and attribute names. Ein Namespace schafft also einen gemeinsamen Kontext für eine Menge von Elementen, Attributen und Datentypen. Ziel dabei ist es, eine einheitliche und eindeutige Bezeichnung der Elemente zu ermöglichen. Vergleichbar zu einem XML-Namespace ist ein Java-Paket, in dem Java-Klassen gruppiert werden, um Namenskonflikte zu verhindern und den Klas- sen einen gemeinsamen Kontext zu geben. Das Standardvokabular von XML-Schema besitzt z.B. den Namespace http://www.w3.org/2001/XMLSchema, der auch schon im einleitenden Beispiel verwendet wurde. Dieser Namespace enthält die grundlegenden Elemente zur Definition neuer Ele- mente, Attribute und Typen. Wenn wir nun weitere Elemente definieren, können wir diese einem anderen, von uns gewählten Namespace zuordnen. Bei der Benennung unserer Ele- mente bleiben wir dadurch völlig frei. 2.1.1.1 Namespaces definieren Eine Namespace-Definition wie beispielsweise  setzt sich zusammen aus: 21
    • 2 Basistechnologien Dem Schlüsselattribut ; dieses Attribut kennzeichnet eine Namespace-Definition. Einem optionalen Präfix, z.B. ; das Präfix kennzeichnet die Zugehörigkeit eines lements zu einem bestimmten Namespace, z.B. gehört das Element  zum oben angegebenen XML-Schema-Namespace. Ein Präfix stellt also eine Art Abkür- zung für den URI eines Namespace dar. Einem URI 3 , z.B. http://jaxb.transparent/customer, der dem Präfix zugewiesen wird. Dieser URI stellt einen eindeutigen Bezeichner für den Namespace dar. 2.1.1.2 XML-Schema und Target-Namespace Es steht uns frei, eigene Namespaces in einem Dokument zu definieren.. Wir können auch ein Schemadokument erstellen, das keine benutzerdefinierten Namespaces enthält, ein so- genanntes „stand-alone schema“. Ein Schemadokument muss jedoch zumindest auf den XML-Schema-Namespace verweisen: Dieser Namespace definiert nämlich die Standardelemente von XML-Schema, die wir zur Definition eines Schemadokumentes nutzen können, z.B. , , , , ,  etc. Nach allgemeiner Konvention erhält er zumeist das Präfix  oder . Da wir später in unserer Anwendung mit mehreren verschiedenen Schemas arbeiten, bietet es sich jedoch an, für jedes Schema stets einen eigenen Namespace zu definieren. Dies hilft, später Elemente eindeutig voneinander abzugrenzen. Um die in einem Schemadoku- ment definierten Elemente, Attribute und Datentypen mit einem bestimmten Namespace zu verknüpfen, deklarieren wir diesen Namespace als sog. Target-Namespace im Wurzel- element. Der Target-Namespace lautet für unser Kundenschema beispielsweise http://jaxb.transparent/customer. Definitionen von Datentypen in einem Schemadokument beziehen sich immer auf genau einen Namespace, den Target-Namespace. Ein Schema darf daher genau einen Target- Namespace definieren. Elemente, die dieses Schema neu definiert, werden automatisch mit diesem Namespace assoziiert. Geben wir keinen Target-Namespace an, so landen die hier definierten Schemaelemente im Standard-Namespace und können von anderen Schemas nicht mehr eingebunden werden. Auf das obige Beispiel bezogen bedeutet dies, dass das Element  auto- matisch dem Namespace http://jaxb.transparent/customer zugeordnet wird. 2.1.1.3 Namespaces in XML-Dokumenten verwenden Bisher haben wir im Schemadokument einen eigenen Namespace durch den Target- Namespace definiert. Wie können wir nun angeben, dass die Elemente in einer Schema- 3 Uniform Resource Identifier 22
    • 2.1 XML-Schema instanz diesen Target-Namespace verwenden? In unserem Kundenbeispiel sieht das fol- gendermaßen aus:           Im öffnenden Tag des Kundenelements  geben wir den URI des Na- mespace an.  Als Präfix ist hier  angegeben, d.h., Elemente mit dem Präfix  werden diesem Na- mespace zugeordnet. Solche Namespace-Deklarationen können für Elemente an beliebiger Stelle in einem XML-Dokument vorgenommen werden. Durch das einleitende Element  und das dazugehörende Attribut  haben wir das -Element mit dem Namespace http://jaxb.transparent/customer assozi- iert. Nun müssen wir noch den Ort des Schemadokuments angeben, auf das sich Elemente aus dem Namespace http://jaxb.transparent/customer beziehen. Dazu deklarieren wir zu- nächst den XMLSchema-instance-Namespace. Dieser Namespace erlaubt uns, ein existie- rendes Schemadokument zu referenzieren.  Das Element  dieses Namespace gibt den Ort des Schemadokuments an. Es kann sich hier wie im Beispiel um einen lokalen Ort handeln oder auch um eine Inter- netadresse.  Mehrere Definitionen werden einfach durch Leerzeichen getrennt, die Anzahl der hier de- finierten Elemente muss daher gerade sein (Namespace + Schemadokument). Wird ein Schemadokument in einem XML-Dokument wie oben beschrieben referenziert, kann die- ses Dokument gegen das angegebene Schema validiert werden. Der Schema-Validierer versucht bei der Validierung, das Schemadokument vom angegebenen Ort zu laden und die Schemainstanz gegen dieses Dokument auf Gültigkeit zu überprüfen. 2.1.1.4 Einen Default-Namespace verwenden Bisher haben wir für jeden Namespace ein Präfix vergeben, so auch für den XML-Schema- Namespace das Präfix . Wir können jedoch auch einen Namespace ohne Präfix definie- ren, dieser ist dann der Default-Namespace für das aktuelle Dokument. Im folgenden Bei- 23
    • 2 Basistechnologien spiel definieren wird den XML-Schema-Namespace als Default-Namespace. Wir können daher das Präfix  vor den -, - und Tags weglassen, da präfixlose Tags mit dem Default-Namespace assoziiert werden.                Noch einmal zum Merken: Mit dem Default-Namespace werden alle präfixlosen Tags verknüpft. Mit dem Target-Namespace werden alle Definitionen von Elementen, Datentypen und Attributen eines Schemas verknüpft. Das obige Schemadokument ist komplett äquivalent zum folgenden Schemadokument, das allerdings keinen Default-Namespace verwendet. Es ist hier eher eine Frage des Stils, wel- che Variante verwendet wird. Bei der Verwendung mehrerer Namespaces in einem Doku- ment ist es jedoch übersichtlicher, alle Namespaces mit einem Präfix zu versehen.                2.1.2 Elementdeklarationen in XML-Schema Bisher haben wir uns mit der allgemeinen Definition und den Namespaces eines Schema- dokuments beschäftigt. Um die in unserer Anwendung verwendeten XML-Daten auf ihre Gültigkeit prüfen zu können, müssen wir erst einmal die Struktur der Daten in unserem Schemadokument festlegen. Innerhalb des -Elements werden wir daher die Ele- mente und Attribute definieren, aus denen sich ein Kundendatensatz zusammensetzt. Dabei soll die Adresse des Kunden noch in Straße, PLZ, Ort und Land unterteilt werden. 24
    • 2.1 XML-Schema 2.1.2.1 Elemente Für unseren Kundendatensatz verwenden wir zunächst Elemente einfachen Typs, d.h. E- lemente, die keine anderen Elemente oder Attribute beinhalten können. Diese Elemente können direkt wie folgt definiert werden.         Ein Element wird also über seinen Namen und Datentyp definiert. Dabei können als Da- tentyp sowohl vordefinierte XML-Schema-Datentypen (mit dem Präfix ) verwendet werden als auch beliebige benutzerdefinierte Datentypen. Oben haben wir bereits einige der gängigen XML-Schema-Datentypen benutzt wie z.B. ,  und . Darüber hinaus stellt XML-Schema noch eine Vielzahl weiterer Datentypen bereit. Diese können in der Datentypreferenz der XML-Schema Recommendation 4 des W3C nachge- schlagen werden. Die zu unserem Schemadokument gültigen Elemente einer Schemainstanz sehen wie folgt aus:         Standardwerte Es lassen sich auch Standardwerte für Elemente definieren. Wird einem solchen Element kein Wert zugewiesen, so trägt es den im Attribut  angegebenen Wert. Ein Beispiel:  Wenn also das so deklarierte Element in einer Instanz dieses Schemas nicht vorhanden sein sollte, so wird an dessen Stelle ein Element mit dem Wert „Germany“ angenommen. 2.1.2.2 Attribute Die Elemente in einem Schema können natürlich auch Attribute definieren. Die Definition eines Attributs gleicht der eines Elements einfachen Typs: 4 z.B. unter http://www.w3.org/TR/xmlschema-2/ 25
    • 2 Basistechnologien  Beispielsweise könnte ein Attribut  für das Element  existieren, das die zu einer Straße gehörige Hausnummer angibt. Die Definition im Schemadokument lautet fol- gendermaßen:       Innerhalb des Elements  geben wir ein Element  an, das unsere Attri- butdefinition enthält. Als Typ des Attributs  ist eine positive Ganzzahl angegeben.  bezeichnet eine benutzerdefinierte Struktur, die weitere Elemente und Attri- bute enthalten kann. Wir werden dieses Konstrukt im nächsten Abschnitt noch näher be- leuchten. Wir sehen aber, dass Elemente mit Attributen 1. immer durch das -Konstrukt beschrieben werden. 2. Attribute selbst als einfache Typen definiert sind. Da das Element  einerseits eine Zeichenkette mit dem Straßennamen enthalten soll, zusätzlich aber auch noch ein XML-Attribut, müssen wir das Attribut  bei der Defi- nition des  setzen. Setzen von  gibt an, dass der komplexe Typ sowohl Text als auch Attribute enthält. Das Attribut  In der obigen Attributdefinition ist außerdem noch das Attribut  gesetzt. Dieses Attribut spezifiziert, dass das Element  auf jeden Fall ein Attribut  enthalten muss. Mögliche Werte für  sind: required: Das Attribut muss für dieses Element vorhanden sein. optional: Das Attribut kann für dieses Element vorhanden sein. prohibited: Das Attribut darf in diesem Element nicht auftreten. Hinweis Das -Attribut kann nur gesetzt werden, wenn – wie oben – ein Attribut innerhalb eines E- lements definiert wird. Nur hier ergibt es auch einen Sinn, da  sich immer auf das äußere Element bezieht. Im XML-Dokument sieht unser Element  mit dem neuen Attribut nun wie folgt aus:  26
    • 2.1 XML-Schema 2.1.2.3 Komplexe Datentypen Bisher haben wir für unseren Kundendatensatz eine flache Struktur aus einfachen Elemen- ten mit vordefinierten Datentypen benutzt. Da unsere Anwendung aber Objekte verwendet, um Daten zu repräsentieren, z.B. ein Adressobjekt mit Straße, PLZ, Ort und Land, erwei- tern wir diese flache Datenstruktur durch einen benutzerdefinierten, komplexen Typ. An- genommen, wir wollen ein XML-Format definieren, bei dem ein Kunde einen komplexen Typ  definiert. Die verschachtelten XML-Elemente sehen dann wie folgt aus:             Durch Definition entsprechender komplexer Typen können wir diese verschachtelte Struk- tur darstellen.                    In diesem Listing haben wir die einzelnen Adressenelemente durch ein Element  ersetzt, das die Adressdaten in einem komplexen Element vom Typ  kapselt. Der komplexe Typ  ist im gesamten Schemadokument wiederverwendbar, da er auf der Hauptebene mit dem -Konstrukt definiert wurde. Strukturierte Typen per complexType deklarieren Solche komplexen Typen, d.h. Elemente, die andere Elemente oder Attribute enthalten können, werden durch das Element  definiert.    27
    • 2 Basistechnologien      Der Typ wird durch einen Namen eindeutig identifiziert. Innerhalb des Elements  können beliebig viele weitere Elemente und Attribute definiert werden. Komplexe Elemente können auch weiter verschachtelt werden. In unserem Beispiel ver- wenden wir außerdem noch ein weiteres Element , das die Ordnung der Unterelemente in unserem Adressobjekt bestimmt. Ordnung mit sequence, all, choice Durch Angabe eines der Schlüsselwörter ,  oder  können wir bestim- men, wie die Elemente eines komplexen Typs verwendet werden sollen. Im obigen Bei- spiel wird durch Angabe des Sequenzindikators  zum Beispiel die Reihenfolge bestimmt, in der die Elemente eines Adressobjekts im XML-Dokument auftreten müssen. Tabelle 2.1 zeigt die möglichen Schlüsselwörter und ihre Auswirkung auf die Ordnung komplexer Typen. Tabelle 2.1 Ordnen von Elementen mit sequence, all und choice Schlüsselwort Effekt  Im XML-Dokument müssen die Elemente in der hier angegebenen Reihenfolge auftreten.  Im XML-Dokument müssen alle Unterelemente dieses Elements auftreten. Die Reihenfolge ist jedoch beliebig.  Im XML-Dokument darf eines dieser Elemente auftreten, nicht jedoch mehrere. In unserer Beispielanwendung können wir diese Indikatoren nutzen, um die Konsistenz der Kundendaten zu gewährleisten. Beispielsweise möchten wir festlegen, dass in einem Kun- dendatensatz alle Adressdaten, d.h. Straße, PLZ, Ort und Land, vorhanden sein müssen, während die Angabe eines Wertes für E-Mail oder Telefon genügen soll. Außerdem soll der Name des Kunden immer am Anfang stehen, gefolgt von den Adressdaten und den üb- rigen Kontaktdaten. Das passende Schemadokument zu diesen Anforderungen sieht folgendermaßen aus:          28
    • 2.1 XML-Schema                Wir haben hier also den Indikator  für die Reihenfolge der Kundendaten ver- wendet. Der Indikator  legt fest, dass alle Adresselemente ausgefüllt sein müssen, wäh- rend der Indikator  die Angabe eines der Elemente  oder  verlangt. Eine gültige Schemainstanz zeigt das folgende Listing.               Das Schemadokument im vorigen Listing weist allerdings noch eine Besonderheit im Ver- gleich zu den bisherigen Dokumenten auf. In XML-Schema gibt es verschiedene Arten, einen Datentyp zu definieren. Lokale vs. globale Definition Bisher haben wir unser Kundendatenelement  folgendermaßen definiert:      Der komplexe Typ wurde einfach innerhalb des Elements  definiert. Dies nennt man lokale Definition oder auch Inlining. Dieser anonyme, komplexe Typ ist nur innerhalb des Elements  sichtbar. Im letzten Schemadokument wurde das Element  jedoch so definiert: 29
    • 2 Basistechnologien     In diesem Fall wird ein komplexer Typ mit dem Namen  in der Wurzel des Schemadokumentes definiert und bei der Definition des Elements über das Attribut  referenziert. Diese globale Definition ermöglicht es, den Typ  auch in anderen Elementen zu verwenden. Das Gleiche gilt natürlich auch für Elemente, die Attribute ent- halten, wie in Abschnitt 2.1.2.2 beschrieben. Die Definition der Datenstruktur für die Stammdaten der Kunden sei damit abgeschlossen. Nun brauchen wir eine weitere Datenstruktur, die Informationen über das Konto eines Kunden darstellt. Hier kommt eine weitere Möglichkeit ins Spiel, Datentypen zu definie- ren: die verfeinerten Basisdatentypen oder Simple Types. 2.1.2.4 Basisdatentypen verfeinern XML-Schema bietet die Möglichkeit, auch für einfache Datentypen weitergehende Typin- formationen zu definieren – die sogenannten „Simple Types“. Diese definieren also keine Unterelemente im Sinne eines strukturierten Datentyps, sondern schränken die möglichen Werte eines der Basisdatentypen wie ,  etc. ein. Beispielsweise können wir hier festlegen, dass für ein Feld nur eine Zahl zwischen 3 und 13 angegeben werden darf oder etwa dass ein Wert nur A, B oder C sein darf. Solche Re- striktionen auf einem der Basisdatentypen können wir mit einer Simple-Type-Deklaration in einem XML-Schema definieren. Die Informationen, die unsere Beispielanwendung über ein Kundenkonto liefert, definiert Daten wie Kontonummer, Kontotyp, das aktuelle Saldo und einen eingeräumten Dispokre- dit. Das zu definierende -Schema für die Kontoinformationen hat also die folgen- de Struktur: Abbildung 2.3 Konto-Datenstruktur Diese Konto-Datenstruktur definieren wir durch ein komplexes Element . Die entsprechende Schemadefinition lautet: 30
    • 2.1 XML-Schema           Zur Abbildung dieser Datenstruktur reichen eigentlich einige Elemente mit vordefinierten Typen wie  oder . Allerdings möchten wir gerne die einzelnen Elemente mit Einschränkungen versehen. Bei- spielsweise soll der Kontotyp nur eine der folgenden Zeichenketten STUDENT, BASIC o- T der PREMIUM enthalten. Daher definieren wir den Datentyp  als   und fügen ein -Element hinzu. Mit dem -Element können wir dann später die benötigten Einschränkungen auf dem angegebenen Basisdatentyp defi- nieren. Zunächst geben wir nur den Basisdatentyp für den Kontotyp mit  an.    Definition Sehen wir uns zunächst die allgemeine Definition einer -Deklaration an.        Wie im ersten Beispiel bereits gezeigt, können wir bei der Definition dieses Datentyps Ein- schränkungen auf einem Basisdatentyp über das -Element definieren. Statt eines vordefinierten Typs wie  ist hier auch die Erweiterung eines anderen benut- zerdefinierten Datentyps möglich. Im -Element werden durch Einfügen so- genannter Facets die Einschränkungen definiert. Im Folgenden wollen wir uns einige die- ser Facets näher anschauen. 2.1.2.5 Einschränkungen mit Facets In XML-Schema besitzt jeder einfache Datentyp eine Reihe von typischen Facets. Der Da- tentyp  z.B. besitzt die Facets   . Im Folgenden sehen wir uns beispielhaft einige dieser Fa- cets an. 31
    • 2 Basistechnologien Enumeration Für die Einschränkung des Kontotyps können wir das -Facet verwenden. Die oben beschriebene Definition des Kontotyps sieht im Schemadokument jetzt folgenderma- ßen aus:        Die drei gültigen Werte für den Kontotyp werden also als Einschränkung des Basistyps  definiert. Eine gültige Schemainstanz kann in einem Element vom Typ   daher nur einen der angeführten Werte angeben. Reguläre Ausdrücke Eine weitere Einschränkung auf den Kontodaten gilt für die Kontonummer. Sie ist als ganzzahliges Attribut des Kontoelements folgendermaßen definiert:      Nun reicht die einfache Restriktion auf eine ganze Zahl nicht aus, üblicherweise sind Kon- tonummern in Deutschland maximal neunstellig und nie negativ. Die Kontonummer soll daher genau neun Stellen mit Ziffern zwischen 0 und 9 besitzen. Dies kann durch eine Ein- schränkung mit dem -Facet erreicht werden.         Das -Facet definiert beliebige reguläre Ausdrücke auf einem Basisdatentyp wie z.B.  oder . Es kann daher sehr flexibel zur Definition von Wertemengen genutzt werden. Die folgenden Beispiele sollen die vielseitige Nutzbarkeit dieser Ausdrü- cke illustrieren. 32
    • 2.1 XML-Schema Tabelle 2.2 Reguläre Ausdrücke Regulärer Ausdruck Beispiel  Chapter 1  b, ab, aab, aaab …  b, ab  xb, yb, zb Wertebereiche Eine weitere gebräuchliche Einschränkung ist die Angabe eines Wertebereiches. Für den Dispokredit legen wir daher einen Wertebereich von 0–10000 Euro fest.       Mit diesen simplen Datentypen für Kontonummer, Kredit und Kontotyp ist unsere einfache Konto-Datenstruktur definiert. Hier noch einmal das gesamte Schemadokument in der Ü- bersicht:                                    33
    • 2 Basistechnologien Es sei noch einmal auf die Möglichkeit hingewiesen, dass auch Attribute global definiert werden können. Das Attribut  für die Kontonummer wird hier inline definiert. Es könnte aber genauso auf oberster Ebene definiert werden.  Dies ermöglicht eine Wiederverwendung des Attributes, indem auf das global definierte Attribut mit dem -Tag verwiesen wird.  Eine gültige Schemainstanz zu unserem -Schemadokument sieht nun folgender- maßen aus:          34
    • 2.1 XML-Schema 2.1.3 Vererbung Abbildung 2.4 Das Aktienportfolio Vererbung und Aufbau von Typhierarchien sind heute in objektorientierten Programmier- sprachen sehr verbreitet. Auch in XML-Schema können wir Datentypen definieren, die hierarchisch aufeinander aufbauen. Sehen wir uns dazu einen weiteren Aspekt unserer Bei- spielanwendung an. Bisher liefert unser Online-Banking-Service die Stammdaten und Kontoinformationen zu einem Kunden. Besitzt ein Kunde zusätzlich noch ein Aktienportfolio, wird auch dieses 35
    • 2 Basistechnologien ausgegeben. Dabei enthält das – zugegeben sehr einfache – Portfolio Wertpapiere und Op- tionen sowie den Gesamtwert aller im Portfolio enthaltenen Wertpapiere und Optionen. Die Datentypen  und  in Abbildung 2.4 repräsentieren die Optionen und Wertpapiere. Eine Wertpapierposition besitzt grundsätzlich einen Namen, eine Wertpa- pierwährung sowie die Anzahl der vorhandenen Stücke und den daraus resultierenden Wert. Eine Option soll die gleichen Elemente besitzen mit dem Unterschied, dass für Opti- onen ein zusätzlicher Optionstyp  und ein Auslaufdatum  angegeben ist. Der Optionstyp gibt an, ob die Option auf einem Wertpapier, einer Währung oder einem Index (z.B. DAX, NASDAQ etc.) definiert ist. Da eine Option damit eine Spezialisierung eines Wertpapiers darstellt, bietet es sich an, dem Datentyp  die Elemente aus  zu vererben, indem wir  von  ableiten. Den Datentyp  für ein Wertpapier definieren wir wieder mit einem .         Um die Elemente dieses Datentyps für den Datentyp  wiederverwenden zu können, geben wir als Basis des Typs  den Datentyp  an. Ausgehend von dieser Basis kann dann die Erweiterung mit zusätzlichen Elementen erfolgen.           Im obigen Listing wurde mit dem Element angege- ben, dass dieser Datentyp eine Erweiterung des Datentyps  darstellt. Innerhalb eines -Elements können wie in einem normalen  weitere Elemen- te definiert werden. In unserem Fall sind dies die Elemente  und . Der Opti- onstyp  stellt dabei wiederum eine Enumeration dar.        36
    • 2.1 XML-Schema 2.1.4 Kardinalitäten Nachdem nun die erforderlichen Datentypen für das Aktienportfolio definiert sind, muss noch definiert werden, wie diese im Portfolio verwendet werden. Abbildung 2.4 ist zu ent- nehmen, dass das Portfolio eine beliebige Anzahl an Optionen und Wertpapieren enthalten kann. Dies wird durch Angabe der Kardinalität  angegeben. In unserem Schemado- kument definieren wir daher jeweils ein Element für Optionen und Wertpapiere.     Durch die Angabe der Attribute  und  bei der Elementdeklaration geben wir eine Unter- und Obergrenze für die Anzahl der erlaubten Elemente an. Der Wert für  wird standardmäßig auf 1 gesetzt, falls das Attribut nicht angegeben wird. Nach Deklaration der Elemente für Wertpapiere und Optionen sieht das gesamte Schema- dokument für unser Aktienportfolio wie folgt aus:                                          37
    • 2 Basistechnologien 2.1.5 Offene Schemas definieren Ein XML-Schema als Datenbeschreibung definieren wir häufig zu Beginn der Anwen- dungsentwicklung. Da wir als Schemaentwickler aber nicht zwangsläufig auch Hellseher sind, können wir unmöglich sofort ein Schema entwickeln, das allen später auftretenden Anforderungen gewachsen ist. Der Nutzer unseres Schemas sollte idealerweise die Mög- lichkeit haben, seine Instanzdokumente mit zusätzlichen Elementen und Attributen zu er- weitern, die nicht zum Schema gehören. Das Schema muss also ein offenes Design besit- zen. Für die Entwicklung offener Schemas eignen sich die im Folgenden beschriebenen Elemente  und , die im XML-Schema-Sprachgebrauch Wild- cards genannt werden. 2.1.5.1 Beliebige Elemente mit xs:any Das Element  definiert eine Art Platzhalter für ein beliebiges Element aus einem angegebenen Namespace. Stellen wir uns vor, wir möchten in einer XML- Dokumentinstanz zu unserem -Schema einen dritten, noch nicht genau definier- ten Wertpapiertyp erlauben. Dieser Typ kann durch ein -Element dargestellt werden. Im Schemadokument für das Portfolio würde das so aussehen.             Der Nutzer unseres Schemadokuments kann jetzt das -Element in seinem In- stanzdokument mit irgendeinem weiteren Element neben den schon definierten Options- und Wertpapierelementen erweitern. Die einzige Beschränkung ist, dass er für das zusätz- liche Element ebenfalls ein Schema angeben muss. Das könnte für ein zusätzliches Ele- ment , das ein Rentenpapier darstellt, so aussehen.                 38
    • 2.1 XML-Schema               Damit das neue Element vom Schema-Validierer akzeptiert wird, geben wir hier also ein entsprechendes Schema unter dem Namespace  an. Doch nicht immer haben wir ein solches Dokument zur Verfügung. Wenn wir das neue Element ohne die Angabe des Schemadokuments einfügen wollen, müssen wir für das - Element das Attribut  setzen. Dieses Attribut steuert das Verhalten der Schema-Validierung für das -Element wie folgt.  "": Dies ist die Standardeinstellung. Das für  an- gegebene Element muss auf jeden Fall gegen ein Schema validiert werden. "": In diesem Fall wird validiert, wenn ein Schema gefunden werden kann, ansonsten wird dieses Element bei der Validierung übersprungen.   "": Hier wird das Element gar nicht validiert, daher kann ein völlig beliebiges Element ohne Schemaangabe deklariert werden. Die folgende Definition lässt also eine beliebige Anzahl Elemente aus irgendeinem Na- mespace zu.  2.1.5.2 Beliebige Attribute mit xs:anyAttribute Das Gegenstück zu  ist bei den Attributen die Wildcard . Es definiert eine Wildcard zur Ersetzung durch beliebige Attribute. Das Attribut   können wir hier analog benutzen, wie für  oben beschrieben. Ein Bei- spiel wäre die Definition beliebiger Attribute für unsere Kundendatensätze. Die Attribute werden in diesem Beispiel nicht validiert, da wir  angeben.             39
    • 2 Basistechnologien Ein gültiges XML-Dokument für diesen Kundentyp ist beispielsweise das folgende.                  Hier definieren wir die Attribute  und  für unsere Kunden. Das erste Attribut de- finiert eine Kundengruppe und das zweite Attribut, ob es sich um einen Neukunden han- delt. 2.1.5.3 any-Erweiterungen auf Namespaces einschränken Die erlaubten Elemente und Attribute innerhalb einer - bzw. - Deklaration lassen sich auch feiner einstellen. Mit dem Attribut  können wir die innerhalb der Deklaration erlaubten Namespaces einschränken. Haben wir eine solche Ein- schränkung definiert, dann wird bei der Schema-Validierung überprüft, ob die hier vor- kommenden Elemente innerhalb der angegebenen Namespaces definiert sind. Der Wert von  ist eine Liste von URI-Bezeichnern der erlaubten Namespaces. Es gibt je- doch einige Schlüsselwörter, die ebenfalls angegeben werden können. : Bezeichnet den Target-Namespace des aktuellen Schemadoku- ments. : Nur lokale Elemente/Attribute ohne Namespace dürfen angegeben werden. : Ein beliebiger Namespace ist möglich. : Ein beliebiger Namespace mit Ausnahme des Target-Namespace darf ver- wendet werden. Die Werte  und  können dabei zusammen mit expliziten URI-Bezeichnern angegeben werden, während die Werte  und  als Ersatz für eine URI-Liste angegeben werden. 2.1.6 Namespaces importieren und referenzieren Bisher haben wir die einzelnen Datentypen unserer Anwendung isoliert voneinander be- trachtet: Kundendaten, Kontodaten und Aktienportfolio wurden in separaten Schemas de- finiert. Als Antwort soll unser Service die gesamten Daten in einem einzigen XML- Dokument liefern. Dazu wollen wir ein Schemadokument definieren, das alle bisher defi- nierten Schemas einbezieht, um die Struktur dieser Antwort festzulegen. 40
    • 2.1 XML-Schema Was wir hier aufbauen wollen, ist also ein „Überschema“, das eine Komposition der bisher definierten Schemadokumente darstellt. Abbildung 2.5 zeigt eine Übersicht über ein sol- ches Schema. Abbildung 2.5 Schemadokument der Antwort des Online-Banking-Service Im Folgenden werden wir uns zwei verschiedene Wege anschauen, wie eine solche Kom- position von Schemas erstellt wird. 41
    • 2 Basistechnologien 2.1.6.1 Komposition eines Schemas mit include Der einfachste Weg, um auf Elemente anderer Schemadokumente zuzugreifen, ist die Verwendung des Elements . Dieses Element erwartet lediglich die Angabe des Ortes, an dem sich das Teilschema befindet.  Mit dem folgenden Codefragment könnten wir unsere Teilschemas in das Antwortschema der Anwendung integrieren:       Elemente und Datentypen der angegebenen Schemas können wir nun genauso verwenden, als hätten wir alle Elemente in einem einzigen Schemadokument definiert. Diese Definition funktioniert jedoch nur, wenn alle Dokumente den gleichen Namespace verwenden, nämlich den des Gesamtschemas http://jaxb.transparent/response. Daher er- wartet das -Element auch keine Angabe eines eigenen Namespace für das ein- zufügende Schemadokument. Für einfache Szenarien ist die Verwendung von  ausreichend. Schemadokumente mit verschiedenen Namespaces müssen allerdings über den -Befehl zusammenge- fügt werden. 2.1.6.2 Komposition eines Schemas mit import In XML-Schema bietet uns das -Tag die Möglichkeit, ein Schemadokument aus Elementen und Datentypen anderer Schemadokumente zusammenzusetzen. Dabei werden die Teilschemas im Gesamtschema referenziert. Auf diese Weise stehen im Gesamtschema alle Elemente und Datentypen der Teilschemas zur Verfügung.   Für unsere Anwendung geben wir daher je ein -Element für Kunden-, Konto- und Portfolioschema an. Neben dem Namespace, der importiert werden soll, geben wir auch den Ort des Schemadokumentes an.       Das folgende Schemadokument zeigt, wie wir die importierten Elemente aus den Teil- schemas nutzen können. Dazu legen wir im Element je ein Präfix für die impor- 42
    • 2.1 XML-Schema tierten Namespaces an. Über diese Präfixe können wir dann die importierten Typen refe- renzieren, z.B. , . Das Dokument definiert also ein Element , das einen Kundendatensatz, Kontoinformationen und ein Portfolio enthält. Die Reihenfolge der Elemente wird dabei wieder über ein Element festgelegt.                       Hinweis - und -Elemente müssen immer vor den Typdefinitionen und Elementde- klarationen eines Schemadokuments stehen. 2.1.7 Eindeutigkeit durch ID und IDREF Das Konzept der Eindeutigkeit von Datensätzen ist aus dem Bereich der Datenbanken hin- länglich bekannt. Beim Erstellen eines Datenbankschemas verwenden wir Schlüsselattri- bute, mit denen wir einen Datensatz eindeutig referenzieren können. Auch in XML- Dokumenten gibt es die Möglichkeit, die Eindeutigkeit von Datensätzen zu gewährleisten. Im DTD-Format gibt es dafür die Datentypen  und , die nur auf Attributebene de- finierbar sind. Die W3C XML-Schemaspezifikation hat diese Datentypen sozusagen ge- erbt, allerdings mit dem Unterschied, dass wir dort sowohl Attribute und Elemente mit den Datentypen  und  definieren können. Bevor wir diese Elemente einzeln näher beschreiben, hier noch einige Eigenschaften, die sie gemeinsam besitzen: Ihr Wertebereich ist der gleiche wie der des Datentyps , d.h., Ziffern am Anfang und das Auftreten von Leerzeichen sind innerhalb der Elemente  und  verboten. Nachteil hierbei: Häufig gibt es Nummern, z.B. Kontonummern, die von Na- tur aus eindeutig sind, diese können allerdings nicht direkt als  verwendet werden. Die Werte von  und  müssen global eindeutig sein, d.h., ein ID-Wert darf nicht im selben Dokument zur Identifikation von zwei Elementen verwendet werden. 43
    • 2 Basistechnologien xs:ID Ein Element oder Attribut vom Typ  stellt einen eindeutigen Bezeichner für das zu- gehörige Element dar. Das folgende Schemafragment definiert ein Element  mit einem Unterelement , das einen Kunden eindeutig identifiziert.          Die folgende Tabelle zeigt dazu jeweils eine gültige und eine ungültige Schemainstanz. Tabelle 2.3 Schemainstanzen mit xs:ID Gültiger Inhalt Ungültiger Inhalt   John John         Johnny John       xs:IDREF Elemente oder Attribute dieses Typs definieren eine Referenz auf ein Element, das wieder- um eine ID mittels  definiert. Im Folgenden definieren wir daher ein Schemafrag- ment, das den eben definierten Kunden um eine Liste mit Freunden erweitert. Diese Freunde sind wiederum vom Typ  und werden durch die ID-Referenz referen- ziert.            Die folgende Tabelle zeigt dazu jeweils eine gültige und eine ungültige Schemainstanz. 44
    • 2.1 XML-Schema Tabelle 2.4 Schemainstanzen mit xs:IDREF Gültiger Inhalt Ungültiger Inhalt       Johnny Johnny John John           Johnny Ben   2.1.8 Dokumentation mit Annotationen Die in unseren Beispielen immer wieder verwendeten XML-Schemadokumente des virtu- ellen Online-Banking-Service sind in diesem Kapitel ausführlich beschrieben. Wie be- kommen aber nun Entwickler, welche die hier definierten XML-Formate in ihren Anwen- dungen einsetzen wollen, Informationen über den Aufbau der gelieferten Daten? Zum ei- nen könnten wird die Schemadokumente veröffentlichen. Dies würde jedoch nur Informa- tionen über die technische XML-Struktur liefern. Es wäre sehr praktisch, wenn wir das XML-Format auch mit weiteren Informationen versehen könnten: Beispielsweise mit Kommentaren, aber auch mit Informationen, die eine spätere technische Verarbeitung der XML-Dokumente beeinflussen. Auch dies kann in ein XML-Schemadokument integriert werden. Über sogenannte Annotationen können wir Dokumentation für Mensch und Ma- schine in ein Schema einfügen.       Das -Element erlaubt das Einfügen von natürlichsprachlicher Dokumentation über das -Element. Im Element  dagegen werden Informationen für Programme angegeben, die ein Schema verarbeiten. Annotationen können allerdings nicht an jeder beliebigen Stelle in ein Schemadokument eingefügt werden. Gültige Orte für Annotationen sind: vor oder nach einer globalen Komponente bei lokalen Komponenten (z.B. innerhalb eines Elements) nur am Anfang      45
    • 2 Basistechnologien         Das -Element werden wir später bei der Verwendung von JAXB noch häufi- ger benötigen. Für JAXB können wir nämlich im -Tag einer Annotation benutzer- definierte Konfigurationseinstellungen vornehmen, welche die Bindung eines Java- Datenmodells an ein XML-Schema näher definieren. Im obigen Beispiel ist bereits eine solche Einstellung dargestellt. 2.1.9 Das fertige Beispielschema In den vorangegangenen Abschnitten haben wir alle nötigen Datenstrukturen für den in unseren Beispielen immer wieder verwendeten Online-Banking-Service durch XML- Schemadokumente definiert. Dabei sind wir ausführlich auf die für uns wichtigen Elemen- te von XML-Schema eingegangen. An dieser Stelle wollen wir noch einmal alle Schema- dokumente auflisten. Diese Auflistung wird uns während der restlichen Kapitel als Refe- renz dienen. 2.1.9.1 Das response-Schemadokument                       2.1.9.2 Das customer-Schemadokument      46
    • 2.1 XML-Schema                     2.1.9.3 Das account-Schemadokument                                   2.1.9.4 Das portfolio-Schemadokument      47
    • 2 Basistechnologien                                      2.2 XPath Der Begriff XPath lässt uns sicher an Dateisysteme denken, die Pfade verwenden, um Da- teien zu lokalisieren. XPath verfolgt ein ganz ähnliches Prinzip, nur dass mit den Pfaden hier Knoten in XML-Dokumenten lokalisiert werden. Denn oft stehen wir vor Fragen wie: „Wo befindet sich das Element X mit der Eigenschaft Y in den 100 Datensätzen meines XML-Dokuments?“ Eine Möglichkeit wäre, mit einer der XML-APIs das gesamte XML-Dokument zu traver- sieren, bis wir auf den gewünschten Knoten stoßen. Das ist allerdings sehr mühsam und in einer Welt von 1001 APIs auch reine Zeitverschwendung. XPath bietet nämlich eine recht intuitive und vor allem mächtige Schnittstelle zur Beschreibung von Elementen und Wer- ten in XML-Dokumenten. Daher ist XPath mittlerweile in einer ganzen Reihe von XML- APIs präsent. So finden wir XPath in den Standards XSLT, XML-Schema und XQuery 5 wieder – und auch in der JAXB. In den folgenden Seiten wollen wir einen kleinen Über- 5 http://www.w3.org/XML/Query 48
    • 2.2 XPath blick über den Standard XPath geben. In JAXB werden nämlich XPath-Ausdrücke bei der Konfiguration der Datenbindung von XML nach Java verwendet. Wie seine großen Geschwister XML und XML-Schema ist auch XPath ein Standard des Webkonsortiums W3C 6 . Mit XPath können wir in deskriptiver Form Informationen über XML-Elemente in einem Dokument abfragen („Wie viele Elemente vom Typ B?“) als auch die Inhalte der Elemente/Attribute selbst („Textinhalt von Element B?“). In dieser Hinsicht besitzt XPath eine gewisse Ähnlichkeit zu den -Statements in SQL, mit denen Inhalte einer Tabelle abgefragt werden können. XPath alleine ist jedoch bei weitem nicht so mächtig wie SQL – dessen Mächtigkeit erreicht vielleicht die Abfragesprache XQuery, die ihrerseits wiederum auf XPath-Ausdrücken basiert. Im folgenden Abschnitt beschränken wir uns auf die Konzepte von XPath, die wir für die sinnvolle Verwendung in JAXB kennen und anwenden müssen. 2.2.1 Die XPath-Sicht auf XML Ein XML-Dokument wird in XPath als eine Baumstruktur angesehen, die aus miteinander verknüpften Knoten besteht. Knoten können aus XML-Konstrukten wie Elementen, Attri- buten und Namensräumen bestehen. Die Knoten wiederum besitzen Werte, die als Text dargestellt sind. Ein Beispiel:             Im obigen Dokument gibt es die folgenden Knoten: Dokumentknoten:  bildet das Wurzelelement des Dokuments Elementknoten: , Wert  Attributknoten: , Wert  Namespace-Knoten: , Wert  Die Knoten besitzen Beziehungen untereinander, wie wir sie aus einem Stammbaum ken- nen. Der Knoten  besitzt z.B. die Kinder (children nodes) , ,  und . Er selbst stellt den Elternteil (parent node) für diese Knoten dar. Außerdem gibt es noch die Geschwisterknoten (sibling nodes), die im Fall des Knotens  z.B. ,  und  sind. Generationsübergreifend gibt es dann 6 http://www.w3.org 49
    • 2 Basistechnologien noch Vorfahren (node ancestors}, das sind für den -Knoten  und  . Umgekehrt sind die Knoten  und  Nachfahren des - Knotens. Mit dieser Sicht auf ein XML-Dokument wollen wir uns jetzt den XPath- Ausdrücken zuwenden. 2.2.2 XPath-Ausdrücke verwenden Mit Xpath-Ausdrücken können wir Knoten in einem solchen XML-Baum beschreiben. Die Syntax von Xpath-Ausdrücken ähnelt der Syntax zur Beschreibung von Dateien in den gängigen Dateisystemen. Gültige XPath-Ausdrücke für das obige Dokument sind bei- spielsweise die folgenden:    Auch wenn die Syntax zunächst vertraut scheint, gibt es einige semantische Unterschiede zwischen der Lokalisierung von XML-Knoten in einem XML-Dokument und der Lokali- sierung von Dateien im Dateisystem. Im ersten Teil eines XPath-Ausdrucks wählen wir einen oder mehrere Knoten aus dem XML-Dokument aus. Knotenauswahl Die folgende Tabelle zeigt die Elemente der XPath-Syntax, die uns für die Knotenselekti- on zur Verfügung stehen. Tabelle 2.5 Elemente der XPath-Syntax Element Bedeutung Beispiel  Selektiert alle Kindknoten des  liefert die Knoten angegebenen Knotens , ,  und .  Bezeichnet den Wurzelknoten  liefert den des Dokuments. Wurzelknoten zurück. Stellt im- mer einen absoluten Pfad dar.  Selektiert alle passenden Knoten  liefert alle Adress- unabhängig von ihrem Ort. knoten, die unterhalb des aktuel- len Knotens liegen.  Bezeichnet den aktuellen Kno- . liefert z.B. , falls dies ten. der aktuelle Knoten ist.  Bezeichnet den Elternknoten  ist wie- des aktuellen Knotens der der -Knoten.  Selektiert ein Attribut.  liefert die Hausnummer zurück. 50
    • 2.2 XPath Bedingungen formulieren mit Prädikaten Die oben dargestellten Syntaxelemente liefern alle Knoten mit einem bestimmten Namen zurück, doch in manchen Fällen wollen wir einen Knoten präziser beschreiben – bei- spielsweise wollen wir nur den ersten Knoten einer Liste abfragen oder nur Knoten, auf die eine bestimmte Bedingung zutrifft. Mit sogenannten Prädikaten können wir aus einer Menge von Knoten eine Teilmenge selektieren. Prädikate werden durch einen booleschen Ausdruck in eckigen Klammern definiert. Zurückgeliefert werden dann alle Knoten, auf die der boolesche Ausdruck zutrifft. Tabelle 2.6 XPath-Ausdrücke mit Prädikaten Ausdruck Bedeutung  Liefert den ersten Kunden aus einer Kundenliste.  Liefert den Kunden mit der E-Mail-Adresse   Liefert den Straßennamen mit dem Hausnummer- Attribut 44 zurück. In unserem Fall „BeerStreet“.  Liefert die Kunden mit Postleitzahlen größer 4000 zurück. Wildcards Wildcards können angegeben werden, wenn wir den genauen Elementnamen nicht kennen oder einfach alle Elemente, Attribute oder sonstige Knoten auswählen wollen. Tabelle 2.7 Wildcard-Ausdrücke Wildcard Bedeutung  Listet alle Adresselemente.  Listet alle Attributknoten im aktuellen Pfad.  Listet alle beliebigen Knoten, dazu gehören auch Namespace-Angaben, Kommentare etc. 2.2.3 Beispiele Da wir immer am schnellsten durch konkrete Beispiele lernen, führen wir hier die gängigs- ten XPath-Ausdrücke auf, die wir für die Arbeit mit JAXB benötigen werden. Die Ausdrü- cke beziehen sich dabei auf das folgende XML-Schemadokument, denn auch Schemas sind wiederum XML-Dokumente, die wir im Verlauf des Buches sogar hauptsächlich be- arbeiten werden. 51
    • 2 Basistechnologien Das Schemadokument                         Auswahl des Wurzelknotens XPath-Ausdruck:  (absoluter Pfad) Selektion:      Auswahl aller global definierten, komplexen Typen XPath-Ausdruck:  (absoluter Pfad) Selektion:           Auswahl aller Elemente XPath-Ausdruck:  (relativer Pfad) Selektion: 52
    • 2.2 XPath                        Auswahl des Elements zipcode XPath-Ausdruck:  (relativer Pfad) Selektion:              2.2.4 XPath in Java Bisher haben wir uns XPath als W3C-Standard angesehen. Der Standard ist zunächst un- abhängig von einer bestimmten Integration in eine Programmiersprache. Wie sieht es nun aus, wenn wir XPath in einem Java-Programm einsetzen wollen? Im Java-Umfeld haben wir eine ganze Reihe von XPath-Implementierungen zur Auswahl. Einige Beispiele sind Xalan 7 , Saxon 8 und Jaxen 9 , die allesamt Open-Source-Projekte darstellen. Seit Java 5 stellt aber auch Sun mit der JAXP 1.3 eine XPath-API bereit, die den Vorteil besitzt, dass 7 http://xalan.apache.org 8 http://saxon.sourceforge.net 9 http://www.jaxen.org 53
    • 2 Basistechnologien wir keine zusätzlichen Bibliotheken benötigen, um XPath-Ausdrücke zu benutzen. Daher stellen wir hier nur diese Variante vor. Eine Baumsicht erstellen Um XPath-Ausdrücke in Java anzuwenden, benötigen wir zuerst eine Java-Sicht auf unser XML-Dokument. Am einfachsten erreichen wir dies durch Parsen des Dokuments in eine DOM-Struktur, wie im folgenden Beispiel dargestellt.      Hier wird also das oben gezeigte XML-Schemadokument in ein Objekt vom Typ   überführt, das unseren XML-Baum darstellt. Auf diese Baumstruktur können wir jetzt XPath-Ausdrücke anwenden. XPath-Abfragen erzeugen und ausführen Für eine simple XPath-Abfrage mit JAXP 1.3 genügt der folgende Vierzeiler.      Wir erzeugen also auch hier eine Factory, die uns ein XPath-Abfrageobjekt bereitstellt. Diesem Objekt übergeben wir dann das XML-Dokument, den XPath-Ausdruck sowie den Typ, den wir als Rückgabe erwarten. Die Methode  wertet die Abfrage aus und gibt die Ergebnisse zurück. In diesem Fall besteht das Ergebnis aus dem Wurzelknoten. Namespace-Präfixe auflösen Eine Zeile haben wir im vorigen Beispiel noch nicht beachtet.  Die Methode  übergibt eine Kontextklasse, die eventuell im Do- kument vorhandene Namespace-Präfixe, wie im obigen Beispiel z.B. das Präfix , in den korrekten Namespace auflöst bzw. umgekehrt. Eine solche Klasse erstellen wir, indem wir das Interface  implementieren. Ein Beispiel für die Implementierung einer solchen Kontextklasse sehen wir hier.       54
    • 2.3 ANT                        Ohne einen solchen Namespace-Kontext kann die XPath-Implementierung keine Na- mespace-übergreifenden Dokumente auswerten. 2.3 ANT ANT ist eine Java-basierte XML-Sprache zur Erstellung von Build-Skripten. Ein Build- Skript nimmt dem Entwickler die alltäglichen Aufgaben wie Kompilieren, Packen und Verteilen von Quellcode ab. Damit lässt sich der Build-Prozess, also der Prozess von der Kompilation des Quellcodes bis zum Deployment und Test der gesamten Anwendung vollständig automatisieren. Vielleicht denken einige jetzt an das -Tool in Unix- Umgebungen. ANT ist genau das, nur ist es nicht an eine bestimmte Plattform gebunden, da es vollständig auf Java basiert. Was hat das nun alles mit JAXB zu tun? Nun, eine Bindung von XML nach Java wird bei JAXB durch die Generierung von Java-Klassen realisiert. Im umgekehrten Fall, der Bin- dung von Java nach XML, kann das zugehörige XML-Schema generiert werden. Diese Generierung passiert zumeist vor der Laufzeit unserer Anwendung und gehört damit zum Build-Prozess. Um nicht jedes Mal mühsam die Generierung durch Aufruf der JAXB- Kommandos in einer Shell anzustoßen, nutzen wir ein ANT-Plugin, das diese Arbeit für uns übernimmt. Aber zunächst sehen wir uns die allgemeine Funktionsweise von ANT an. 2.3.1 ANT-Übersicht Ähnlich wie bei anderen Build-Werkzeugen wird auch bei ANT ein Skript aufgerufen, das den gesamten Build-Prozess abarbeitet. Dieses Skript wird entsprechend auch Build-Skript 55
    • 2 Basistechnologien genannt und ist, wie könnte es anders sein, in XML geschrieben. Neben dem Build-Skript sollten wir noch einige andere Begriffe kennen: Projekt: Jedes Build-Skript definiert ein Projekt, das den Build-Prozess für eine be- stimmte Anwendung darstellt. Das Projekt definiert ein Standard-Target (Default Tar- get). Falls kein anderes Target beim Aufruf angegeben ist, wird dieses Target aufgeru- fen. Target: Ein Projekt enthält also mindestens ein Target, das beim Ausführen des Build- Skriptes gestartet wird. Ein Target compile kann beispielsweise die Kompilierung des Quellcodes übernehmen, ein anderes Target deploy den kompilierten Quellcode in ein JAR-Archiv verpacken. Targets sind so konfiguriert, dass sie sich untereinander aufru- fen. So können wir Abhängigkeiten zwischen den Targets definieren, etwa dass das Target deploy von dem Target compile abhängt. So kann z.B. das Verpacken des Codes erst nach einer vorherigen Kompilation der Quellen stattfinden. Man sagt hier „die Verpackung ist abhängig von der Kompilierung“. Dabei werden die einzelnen Targets möglichst nur ausgeführt, wenn sich relevante Quellen geändert haben. Task: Die Funktionen, die innerhalb eines Targets aufgerufen werden, sind in Tasks definiert. Ein Task kann z.B. den Java-Compiler aufrufen, den JAXB Schema- Compiler oder den Schema-Generator. Es gibt viele bereits in ANT eingebaute Tasks, die von einem Target aus aufgerufen werden können. Benutzerdefinierte Tasks, wie z.B. die JAXB Tasks, müssen erst im Build-Skript definiert werden, bevor sie benutzt werden können. 2.3.2 Installation und Aufruf ANT kann entweder im Binärformat oder als Quellcode von der ANT-Webseite 10 herun- tergeladen werden. Der Einfachheit halber werden wir im Folgenden die Existenz eines fertig kompilierten Binärpakets voraussetzen. Dies liegt zumeist in gepackter Form z.B. als ZIP-Archiv vor. Dieses ZIP-Archiv besitzt die folgende Verzeichnisstruktur: bin: Enthält die ANT-Kommandozeilenskripte. docs: Umfangreiches Benutzerhandbuch und API-Dokumentation etc: Enthält XSL-Erweiterungen. lib: Optionale ANT-Tasks und Abhängigkeiten Installation Unabhängig vom verwendeten Betriebssystem sind zur Installation von ANT die folgen- den Schritte notwendig: 1. Entpacken des ANT-Archivs in ein beliebiges Verzeichnis. 2. Das Unterverzeichnis bin in den Pfad aufnehmen. 10 http://ant.apache.org 56
    • 2.3 ANT 3. Eine Umgebungsvariable mit dem Namen ANT_HOME erstellen, die auf das Installati- onsverzeichnis zeigt. 4. Falls noch nicht vorhanden, eine Umgebungsvariable JAVA_HOME erstellen, die auf das Installationsverzeichnis des JDK zeigt. Aufruf Per Kommandozeile können wir nun den ANT-Befehl aufrufen. Die folgende Syntax führt das unter [] angegebene Target des Projekts in der Datei build.xml aus.  Wenn das Build-Skript den Standardnamen  trägt, kann der Parameter  auch weggelassen werden. 2.3.3 Häufig verwendete Elemente 2.3.3.1 Properties definieren Es ist häufig sinnvoll, in einem Build-Skript Variablen als Platzhalter zu definieren, da z.B. Verzeichnisnamen an vielen Stellen im Skript benötigt werden. Um Redundanz zu vermeiden, können diese Verzeichnisnamen mit einer -Deklaration als Variablen in einem ANT-Skript definiert werden:  Dieses Beispiel definiert eine Property , die auf das Verzeichnis  zeigt. Im gesamten Skript kann diese Variable nun durch Angabe von  referenziert wer- den. 2.3.3.2 javac-Task Um Quellcode zu kompilieren, existiert in ANT der -Task, dem ein Quell- und ein Zielverzeichnis sowie ein Klassenpfad übergeben werden. Der Task kompiliert Java- Quellcode und legt diesen im Zielverzeichnis ab.   2.3.3.3 Der Klassenpfad Für einige Tasks, wie oben bei , muss in ANT ein Klassenpfad definiert werden. Da- für kann zum einen explizit das -Element mit einem verschachtelten  Element benutzt werden: 57
    • 2 Basistechnologien    Eine andere Möglichkeit ist die Referenzierung eines existierenden Pfades. Das folgende Beispiel legt einen Pfad mit dem -Element an und verweist bei der Definition des Klassenpfades auf den vorher definierten Pfad. Dadurch kann die redundante Definition von Klassenpfaden vermieden werden:      2.3.4 Benutzerdefinierte Tasks Eines der mächtigen Merkmale von ANT ist, dass wir die verfügbaren Elemente durch ei- gene Task-Implementierungen nach dem Baukastenprinzip erweitern können. Um ANT mit benutzerdefinierten Tasks zu erweitern, muss der betreffende Task im aktuellen Pro- jekt erst definiert werden. Dies kann über die folgenden zwei Definitionen geschehen:         Bei der Task-Definition werden ein Name für den Task, der vollständige Klassenname der Implementierung und der zugehörige Klassenpfad angegeben. Im obigen Beispiel wird einmal ein Klassenpfad innerhalb der Definition angelegt und beim anderen Mal ein exis- tierender Pfad verwendet. Damit ist der Task vollständig definiert und kann im weiteren Verlauf unter dem angegebenen Namen verwendet werden. 2.3.5 xjc und schemaGen Tasks Für die komfortable Integration der JAXB-Funktionalität in einen ANT-basierten Build- Prozess gibt es zwei Tasks: den -Task und den -Task. Ersterer integriert den Schema-Compiler und Letzterer den Schema-Generator von JAXB in ANT. Wie diese Tasks definiert werden, ist in der Referenz genau beschrieben. Sie werden bei der Refe- renzimplementierung der JAXB in einem eigenen JAR-Archiv  mitgelie- fert. Sehen wir uns daher ein Beispiel an, das diese Task-Definition in einem Gesamtkon- text verwendet. 58
    • 2.3 ANT 2.3.6 Ein Beispiel                                      Das obige Listing zeigt ein Projekt mit dem Namen , das ein Standard-Target  definiert. Dieses Target automatisiert den gesamten Build-Prozess vom Aufruf des Schema-Compilers über das Kompilieren der Anwendung bis zum Archivieren der An- wendung in einer JAR-Datei. Dabei sind die Targets über Abhängigkeiten per  verknüpft, d.h., zuerst wird das -Target aufgerufen, dann  und erst zuletzt . Zu Beginn des Skripts werden einige Variablen definiert, die Verzeichnisse darstel- len, die in den einzelnen Targets benutzt werden. Außerdem wird der Klassenpfad zu den JAXB-Bibliotheken global definiert, da der Java-Compiler und Schema-Compiler beide diesen Pfad benötigen. Das Skript führt nun die folgenden Aktionen aus: Generieren der JAXB-Java Beans aus dem Schema in das Verzeichnis  Kompilieren der JAXB-Klassen und des übrigen Anwendungscodes in das Verzeichnis  59
    • 2 Basistechnologien Verpacken der kompilierten Klassen in ein JAR-Archiv namens  Als Datei  abgespeichert, lässt sich dieses Skript nun von der Kommandozeile mit dem folgenden Befehl aufrufen:  Nutzer der weitverbreiteten integrierten Entwicklungsumgebung Eclipse können solche Build-Skripte natürlich auch bequem mit der in Eclipse integrierten ANT-Unterstützung starten. Für weiterführende Informationen über die Verwendung von ANT sei auf die sehr ausführ- liche Dokumentation in der ANT-Distribution verwiesen. Der Aufruf des Schema- Generators funktioniert ähnlich. Hier nur ein kurzes Listing mit dem entsprechenden Auf- ruf.                  60
    • 3 Hallo JAXB! In den vorangegangenen Kapiteln haben wir uns mit den Voraussetzungen und den theore- tischen Grundlagen zur JAXB beschäftigt. Jetzt wenden wir uns endlich der Praxis zu. Dieses Kapitel zeigt, wie wir eine funktionierende JAXB-Entwicklungsumgebung aufset- zen, mit der wir die Beispiele in dem folgenden Programmiertutorial erstellen und nach- vollziehen können. Anhand des allseits bekannten „Hallo Welt!“-Beispiels probieren wir diese Entwicklungsumgebung gleich aus. Das „Hallo Welt!“-Beispiel wird uns gleichzei- tig einen ersten Überblick über die Vorgehensweise bei der XML-Java-Datenbindung mit JAXB geben. Die dabei verwendeten API-Komponenten sind im folgenden Programmier- tutorial detailliert erklärt. Wir werden daher in diesem ersten Beispiel nicht näher darauf eingehen, sondern uns nur auf einen Round-Trip, also eine Bindung von Java nach XML und zurück, konzentrieren. 3.1 Systemvoraussetzungen Bevor wir loslegen können, brauchen wir einige Softwarepakete auf unserem System: Java Standard Edition 5: JAXB 2.0 benötigt die Java Standard Edition 5 (JSE5) oder besser, da JAXB intensiven Gebrauch von den in Java 5 eingeführten Annotationen und Generics macht. Die aktuelle Version der JSE5 ist unter der folgenden URL erhält- lich: http://java.sun.com/javase/downloads/index.jsp Apache ANT: Für den Schema-Compiler und den Schema-Generator existiert in der JAXB-Referenzimplementierung eine Unterstützung durch ANT-Tasks. Diese müssen in einem Projekt nicht zwangsläufig genutzt werden, sind aber wesentlich komfortabler als die Kommandozeilenvariante. Daher ist es ratsam, in der JAXB- Entwicklungsumgebung mit ANT zu arbeiten. ANT ist erhältlich unter der folgenden URL: http://ant.apache.org/. Wir haben dem Thema ANT im vorigen Kapitel eine kurze Einführung gewidmet. Dort ist auch die Installation ausführlich beschrieben. JAXB Reference Implementation: In diesem Buch setzen wir auf der zurzeit aktuellen JAXB Reference Implementation 2.0.2 von Sun auf. Diese bietet die momentan voll- 61
    • 3 Hallo JAXB! ständigste Implementierung der JAXB-Spezifikation und ist erhältlich unter der fol- genden URL: https://jaxb.dev.java.net/ Eine alternative JAXB-Implementierung gibt es von Apache mit JaxMe2, die unter un- ten stehender URL bezogen werden kann. Hier kann es im Detail zu Unterschieden zwischen den in diesem Buch beschriebenen Funktionalitäten und denen der durch die JaxMe2-Implementierung gebotenen Funktionalität. Die Implementierung erhalten Sie unter http://ws.apache.org/jaxme/ 3.2 Die Entwicklungsumgebung einrichten 3.2.1 JAXB-Referenzimplementierung installieren Nachdem wir die aktuelle Referenzimplementierung von Sun bezogen haben, sollten wir eine Datei in der Form  in Händen halten, metaphorisch wohlgemerkt. Dieses JAR-Archiv enthält die komplette JAXB-Distribution. Installiert wird dieses Paket mit einem Aufruf von der Kommandozeile, z.B.  Nach Akzeptieren der Lizenzvereinbarung wird der Inhalt in die folgende Verzeichnis- struktur des aktuellen Verzeichnisses entpackt. jaxb-ri-20060607 bin: Enthält die Kommandozeilenskripte für Schema-Compiler/-Generator docs: Dokumentation und Javadoc der API lib: JAXB-Bibliotheken und Quellcode-Archive samples: Beispielanwendungen mit JAXB 3.2.2 Die JAXB-Bibliotheken einbinden Für die Arbeit mit der JAXB-Referenzimplementierung müssen sich die JAR-Bibliotheken aus dem lib-Verzeichnis der Installation auf dem Klassenpfad unserer Anwendungen be- finden. Die JAXB-Referenzimplementierung enthält die folgenden JAR-Bibliotheken. jaxb-api.jar: API-Klassen der JAXB-Spezifikation jaxb-impl.jar: Klassen der JAXB-Referenzimplementierung jsr173_1.0_api.jar: XML Streaming API, z.B.  activation.jar: Abhängigkeit zur Java Beans Activation API jaxb-xjc.jar: XJC Schema-Compiler und Schema-Generator jaxb1-impl.jar: JAXB 1.0-Kompatibilitätsklassen Für unsere Beispielanwendungen benötigen wir die folgenden Bibliotheken zur Laufzeit. 62
    • 3.2 Die Entwicklungsumgebung einrichten jaxb-api.jar jaxb-impl.jar jsr173_1.0_api.jar activation.jar Um Klassen und Schemas zu generieren, benötigen wir die folgende Bibliothek zur Com- pile-Zeit auf dem Klassenpfad. jaxb-xjc.jar Für Anwendungen, die auf der Version 1.0 der JAXB aufsetzen, muss noch die Bibliothek jaxb1-impl.jar hinzugefügt werden. Wir fügen also im Standardfall die ersten fünf Bibliotheken der Umgebungsvariablen CLASSPATH hinzu. Damit sind wir auf der sicheren Seite. Hinweis Wenn wir mit einer Entwicklungsumgebung wie Eclipse arbeiten, ist es hilfreich, die ebenfalls im lib-Verzeichnis enthaltenen Quellcode-Archive auf den Klassenpfad zu legen. Dadurch können bequem die Javadoc-Kommentare zu den einzelnen Komponenten eingesehen werden. 3.2.3 Die Struktur des Beispielprojekts Wir empfehlen sehr, die in diesem Buch enthaltenen Beispiele praktisch auszuprobieren. Der dafür erforderliche Quellcode kann in Form eines Beispielprojekts auf der Webseite dieses Buchs heruntergeladen werden. An dieser Stelle sei daher kurz der Aufbau des Bei- spielprojekts dargestellt. Die Codebeispiele sind nach Kapiteln in einzelne Pakete unter- teilt. Unter den Kapitelpaketen sind die Beispiele zu einzelnen Abschnitte in eigenen Un- terpaketen zusammengefasst. Das Java-Paket, in dem sich der Quelltext befindet, ist im Quelltextauszug stets mit abgedruckt. Die Ordner des Beispielprojekts besitzen den folgenden Inhalt. src: Quellcode nach Kapiteln unterteilt src-gen: durch den Schema-Compiler generierte Klassen lib: JAXB-Bibliotheken schema: Verzeichnis mit XML-Schemas und XML-Dokumenten schema-gen: durch den Schema-Generator erzeugte XML-Schemas build.xml: Build-Skript für das Banking-Service-Schema buildHelloWorld.xml: Build-Skript für das „Hallo Welt!“-Beispiel Hinweis Eclipse-Nutzer können das Beispielprojekt ganz einfach importieren und direkt verwenden, ohne den Klassenpfad verändern zu müssen. Auch ist hier die ANT-Unterstützung schon ein- gebaut, so dass dem Entwickler einiges an Konfiguration abgenommen wird. 63
    • 3 Hallo JAXB! 3.3 Am Anfang steht immer: Hallo Welt! Nachdem die Entwicklungsumgebung jetzt rein technisch lauffähig ist, können wir unser erstes JAXB-Beispiel in Angriff nehmen. Dazu bedienen wir uns des Klassikers der In- formatikliteratur, nämlich einer Variante des „Hallo Welt!“-Beispiels. Es dreht sich bei diesem Beispiel schlicht und ergreifend um ein XML-Dokument, das ein  Element mit einer entsprechenden Nachricht  enthält. Anhand dieses Beispiels werden wir die möglichen Szenarien der Datenbindung durchspielen. Zuerst werden wir eine existierende Java Bean an ein XML-Schema binden. Danach gehen wir den umge- kehrten Weg und erzeugen aus einem bestehenden XML-Schema eine entsprechende Java- Repräsentation. Um den Schema-Compiler bzw. Schema-Generator aufzurufen, bedienen wir uns der entsprechenden ANT-Tasks. 3.3.1 Der Weg von Java zu XML Nehmen wir einmal an, wir besitzen als Ausgangspunkt eine simple Java Bean, die wir gerne an ein XML-Datenformat binden wollen. Die Java Bean heißt  und hat die folgende Struktur.               Das ist so weit nichts Ungewöhnliches. Um diese Java Bean an ein XML-Element binden zu können, müssen wir mit JAXB nur eine einzige Änderung machen. Durch Hinzufügen einer Annotation  lassen wir JAXB wissen, dass es sich bei dieser Klas- se um das Wurzelelement eines XML-Dokuments handelt. Die Klasse sieht jetzt folgen- dermaßen aus.      64
    • 3.3 Am Anfang steht immer: Hallo Welt!           Das ist auch schon alles, was wir verändern müssen. Für die Eigenschaften der Java Bean und die später erzeugten Namen im XML-Dokument vertrauen wir auf die Standardein- stellungen der JAXB-Implementierung. Mit dem folgenden kleinen Beispielprogramm er- zeugen wir jetzt aus einem -Objekt ein entsprechendes XML-Dokument.                   Nachdem wir einige Initialisierungen vorgenommen haben, erzeugen wir hier einfach eine neue Instanz der Klasse , die als Nachricht den Wert „Hello world!“ be- kommt. Diese Instanz übergeben wir einer -Instanz, die für uns die Transfor- mation übernimmt. Das fertige XML-Dokument wird dann auf der Konsole ausgegeben.     Das war ein Kinderspiel oder? Im Prinzip wird aber auch bei komplizierteren Bindungen nach dem gleichen Schema vorgegangen. Existierende Java Bean mit Annotationen versehen Instanz der Java Bean erzeugen Instanz an den  übergeben und XML-Dokument ausgeben 65
    • 3 Hallo JAXB! Apropos Schema, wo ist hier eigentlich die Bindung an ein XML-Schema, von dem vorher gesprochen wurde? Nun, JAXB erzeugt hier aus der Java Bean  ein Schema, das wir uns bei Bedarf auch ausgeben lassen können. Dafür gibt es neben dem programma- tischen Weg über die API oder die Kommandozeile auch einen ANT-Task, den wir an die- ser Stelle kurz vorstellen wollen. Wir geben hier wirklich nur ein kurzes Beispiel an, die einzelnen Konfigurationsmöglichkeiten des -Tasks sind in der Referenz be- schrieben. Schema erzeugen mit dem schemaGen-Task                         Mit diesem kleinen ANT-Skript können wir jetzt das Schema durch Ausführen des Targets  erzeugen und in der angegebenen Datei abspeichern. Das zu unserer kleinen Java Bean passende Schema hat nun die folgende Struktur.           66
    • 3.3 Am Anfang steht immer: Hallo Welt! 3.3.2 Der Weg von XML zu Java Der vorangegangene Abschnitt hat die Bindung einer Java-Klasse an ein XML-Schema gezeigt. Dieser Weg existiert erst seit JAXB 2.0. Jetzt sehen wir uns den klassischen Weg an, nämlich die Bindung eines existierenden XML-Schemas an ein generiertes Java- Datenmodell. Ausgangspunkt ist hier jetzt das XML-Schema statt der Java Bean.             Das Schema beinhaltet die gleiche Information wie zuvor unsere Java Bean. Ein Element  wird als Wurzelelement deklariert und besitzt ein Unterelement , das die eigentliche Nachricht beinhaltet. Aus diesem Schema werden wir jetzt unsere Java- Repräsentation erzeugen. Dazu bemühen wir den Schema-Compiler, der genau wie der Schema-Generator über die API, über die Kommandozeile und einen ANT-Task gestartet werden kann. Das folgende Beispiel zeigt, wie wir den Schema-Compiler mit einem klei- nen ANT-Skript dazu bringen, Java-Code aus dem obigen Schema zu generieren.                        67
    • 3 Hallo JAXB!      Die genaue Funktion des ANT-Tasks ist recht ausführlich in der Referenz beschrieben, da- her wollen wir hier nur kurz darauf eingehen. Mit dem Target  wird der Schema- Compiler für ein gegebenes Schema gestartet. Der Schema-Compiler liest das Schema und leitet daraus die entsprechenden Klassen ab. Führen wir dieses Skript nun aus, erhalten wir die folgende Klasse HelloWorld.                    Wir sehen, dass der Schema-Compiler noch einige weitere Annotationen zu dieser Klasse hinzufügt, als wir das im letzten Abschnitt selbst getan haben. Ansonsten ist die Klasse a- ber identisch mit unserer selbst geschriebenen Java Bean . Daher können wir auch genauso damit umgehen, denn immerhin handelt es sich hier um eine ganz gewöhnli- che Java Bean. Was uns natürlich am meisten interessiert, ist, wie wir die Inhalte aus ei- nem XML-Dokument in eine Instanz dieser Klasse bekommen. Genau dies sehen wir uns jetzt an. Angenommen, wir bekommen wieder das folgende XML-Dokument mit der „Hel- lo world!“-Nachricht als Eingabe.     Dieses Dokument verarbeitet das folgende Listing in eine Instanz vom Typ . Wir führen hier also ein Mini-Unmarshalling durch.   68
    • 3.4 Zusammenfassung                Diese Minianwendung ist ähnlich wie das erste Beispiel aufgebaut. Nach einigen Initiali- sierungen erzeugen wir mit Hilfe des -Objektes aus dem XML-Dokument  eine Instanz vom Typ . Diese Instanz besitzt jetzt den Inhalt der Elemente aus dem XML-Dokument. Die Ausgabe der Nachricht  liefert uns daher wieder die simple Nachricht . 3.4 Zusammenfassung Für die JAXB-Entwicklungsumgebung werden die Bibliotheken jaxb-api.jar, jaxb- impl.jar, jsr173_1.0_api.jar, activation.jar, und jaxb-xjc.jar auf dem Klassenpfad be- nötigt. Die Beispielanwendungen dieses Buches sind auf der Buch-Webseite zum Download erhältlich. Die Bindung von Java nach XML geschieht über Java-Klassen mit JAXB- Annotationen. Die Bindung von XML nach Java geschieht über das Generieren von JAXB-Klassen mit dem Schema-Compiler Für die Ausführung von Schema-Compiler und Schema-Generator gibt es ANT- und Kommandozeilenskripte. 69
    • 4 JAXB-API In diesem Kapitel wird es so richtig losgehen. Stück für Stück werden wir durch praktische Beispiele die Möglichkeiten der JAXB erschließen. Dabei wird die im Kapitel zu XML- Schema vorgestellte Domäne des Online-Banking-Service der rote Faden sein, an dem sich die Beispiele orientieren. Als Erstes werden wir uns der JAXB-API widmen. Die folgende Abbildung zeigt einen typischen Anwendungsfall unseres Online-Banking-Service und die verwendeten JAXB-API-Elemente. Client Online-Banking-Service JAXBContext / Unmarshaller JAXBContext / Marshaller Abbildung 4.1 Aufruf des Online-Banking-Service Die XML-Dokumente, die wir hier verwenden, basieren auf dem gleichen Gerüst aus Schemadokumenten, das bereits im XML-Schema-Kapitel aufgebaut wurde. Die am Schluss des XML-Schema-Kapitels aufgeführte Übersicht über die einzelnen Schemado- kumente soll uns im weiteren Verlauf als Referenz für die benutzten Schemas dienen. Anhand dieses Schemas und der zugehörigen JAXB-Klassen stellen wir die Voraussetzun- gen und Grundlagen vor, die wir brauchen, um die API zu nutzen. Danach widmen wir uns den eigentlichen Funktionalitäten, die uns die JAXB-API bietet, wie z.B. das Unmarshal- ling und Marshalling von XML-Dokumenten. Danach stellen wir die Funktionalitäten und Aspekte vor, die sowohl beim Marshalling als auch beim Unmarshalling verwendet werden wie beispielsweise die Validierung,  71
    • 4 JAXB-API  und . Am Ende des Kapitels sollten wir damit den prakti- schen Einsatz der gesamten JAXB-API kennen. 4.1 Die ersten Schritte Die wichtigen Klassen der Laufzeit-API der JAXB, die wir in den ersten Schritten be- schreiben werden, sind: : Jeder lesende bzw. schreibende Zugriff auf XML erfolgt implizit über eine -Instanz. : Eine Klasse, mit der wir Informationen zur XML-Bindung von Java-Objekten abfragen können. die durch den Schema-Generator angelegte Klasse , mit der wir pro- grammatisch die Java-Objekte eines XML-Dokuments anlegen können. 4.1.1 Am Anfang war der JAXBContext Der  bildet den Einstiegspunkt für die JAXB-API. Eine Applikation, die auf eine Datenbindung mit JAXB zugreifen möchte, muss als Erstes ein Objekt vom Typ  erzeugen. Der  verwaltet nämlich die Informationen über die Datenbindung zwischen einem Java-Modell und einem oder mehreren XML-Schemas. Dazu speichert die -Instanz implizit eine bidirektionale Abbildung zwischen global deklarierten Elementen im Schema und den entsprechenden Java-Klassen. Dies er- möglicht z.B. dem , ein XML-Element auf den korrekten Typ abzubilden. Für unsere Beispielanwendung sollten wir uns dieses Mapping einmal ansehen. Tabelle 4.1 Abbildung von globalen Elementen im JAXBContext XML-Element Namespace Abbildung im JAXBContext <response> http://jaxb.transparent/response Klasse Response <customerElement> http://jaxb.transparent/customer Klasse Customer <accountElement> http://jaxb.transparent/account Klasse Account <portfolioElement> http://jaxb.transparent/portfolio Klasse Portfolio Die Tabelle zeigt, dass nur die global definierten Elemente aus den vier Schemadokumen- ten in der Abbildung vorhanden sind. Nur diese Elemente kommen als Wurzel eines XML- Dokuments für diese Schemadokumente in Frage. Unser Online-Banking-Service muss also als Erstes ein -Objekt definieren, um eine Antwort auf eine Anfrage erstellen zu können. Dieses Objekt bietet ihm dann die Möglichkeit, über Factory-Methoden entsprechende Service-Objekte (,   etc.) für die einzelnen API-Funktionalitäten zu erstellen. Hier eine Übersicht 72
    • 4.1 Die ersten Schritte über die verschiedenen Möglichkeiten, einen  zu erzeugen, sowie die ver- schiedenen Service-Objekte und deren Factory-Methoden:                    4.1.1.1 Einen JAXBContext anlegen Ein -Objekt wird über die Factory-Methode  erzeugt. Die -Klasse selbst ist eine abstrakte Klasse. Welche konkrete Implementierung hier von der -Methode zurückgegeben wird, hängt von der verwendeten JAXB-Implementierung ab und sollte sich nicht auf deren Verwendung auswirken. Sie wird im Fall der Referenzimplementierung aus der Datei  gelesen. Wie aus dem Listing oben zu erkennen ist, gibt es eine ganze Reihe von - Methoden mit verschiedenen Signaturen. Zu den wichtigsten Methoden ist hier jeweils ein Beispiel abgedruckt. JAXBContext unter Verwendung des Paketnamens erzeugen Wir können eine neue -Instanz anhand einer Zeichenkette erzeugen. Die Zei- chenkette beschreibt ein oder mehrere Java-Pakete, deren Klassen über JAXB an XML ge- bunden werden sollen.     73
    • 4 JAXB-API Dieser Methode übergeben wir einen Kontextpfad, der aus einem vollqualifizierten Paket- namen oder aus mehreren Paketnamen besteht, die wir per Doppelpunkt trennen. Diese Pakete enthalten die Java-Klassen, die ein oder mehrere zu bindende XML-Schemas reprä- sentieren. Der  ist nach diesem Aufruf mit allen definierten Klassen initialisiert und kann nun Instanzen dieser Java-Klassen in XML umwandeln und umgekehrt. JAXBContext unter Verwendung eines anderen Classloaders erzeugen Der Aufruf  nutzt den  des aktuellen Threads, um die Klassen im angegebenen Paket zu lokalisieren. Falls eine andere -Instanz benutzt werden soll, kann diese der folgenden Variante der -Methode übergeben werden:    JAXBContext anhand von Java-Klassen erzeugen Besonders im Fall der Bindung eines Schemas an ein existierendes Datenmodell ist die folgende Variante der -Methode zu erwähnen. Diese erwartet anstelle eines Paketnamens die Angabe einer gewöhnlichen Java-Klasse in Form einer -Instanz.   Hier wird z.B. die Klasse  angegeben, die das Wurzelelement für die Antwort des Online-Banking-Service darstellt. Dadurch wird ein  mit der Klasse   und allen von ihr referenzierten Klassen initialisiert. 4.1.1.2 Viele Threads, ein JAXBContext Sicher wird sich der ein oder andere fragen, ob der  für jede Verarbeitung neu angelegt werden muss. Das Erzeugen des -Objektes ist ein recht auf- wendiger Vorgang, da die Bindungsinformationen für alle Klassen, die dem Kontext zuge- ordnet sind, zunächst ermittelt werden müssen. Daher sollte das Objekt nach Möglichkeit wiederverwendet werden. Die JAXB-Spezifikation schreibt vor, dass eine Implementierung der -Klasse threadsafe sein muss. Dadurch kann eine Instanz des  von beliebig vielen Threads genutzt werden. In unserem Beispiel könnte der Online-Banking-Service ein ein- ziges Kontextobjekt benutzen, um beliebig viele Clients zu bedienen. Also statt wie in dem folgenden Quelltextauszug in jedem Methodenaufruf eine neue Instanz anzulegen: 74
    • 4.1 Die ersten Schritte      ist es erlaubt und performanter, diese statisch anzulegen, wie wir das im unten abgedruck- ten Quelltext machen:      4.1.2 Die Klasse JAXBIntrospector verwenden Eine der Klassen, die auf Anfrage durch eine -Implementierung instanziiert wird, ist die Klasse . Diese Hilfsklasse bietet Methoden, mit denen wir unbekannte Java-Objekte auf eine XML-Bindung hin prüfen können.       Den Einsatz der oben genannten Methoden schauen wir uns näher an. Die folgenden Bei- spiele setzen voraus, dass ein XML-Dokument wie folgt per Unmarshalling in ein Objekt  vom Typ  überführt wird.                          75
    • 4 JAXB-API isElement Mit der Methode  können wir feststellen, ob ein beliebiges Objekt ein durch diesen Kontext gebundenes XML-Element darstellt. Objekte, für die dies zutrifft, sind: Objekte vom Typ  Objekte, deren Klasse eine Annotation  besitzt Beispielsweise liefert der Aufruf  den Rückgabewert , weil  als Element auf der Hauptebene in unserem Schema definiert wurde und daher die Annotation  trägt. Der folgende Aufruf  liefert den Wert . Auch das ist korrekt, da der Datentyp  nicht mit der An- notation  markiert wurde und daher auch nicht als Wurzelelement eines XML-Dokuments in Frage kommt. Wir können aber manuell ein Element aus dem   Objekt erzeugen, indem wir es in einen Wrapper vom Typ  verpacken, auf den wir später noch näher eingehen werden:     Das obige Beispiel liefert jetzt auch  als Ausgabe. getElementName Für alle Objekte, für die  den Wert  zurückliefert, kann mit der Methode  der Name des Elements im XML-Dokument bezo- gen werden.  Der Aufruf liefert den Namen des Elements in Form eines -Objekts, dessen - Darstellung so aussieht:  getValue Diese wohlgemerkt statische Methode liefert den „Wert“ eines an XML gebundenen Java- Objekts. Wie oben erwähnt, kann eine solche Bindung in zwei verschiedenen Formen auf- 76
    • 4.1 Die ersten Schritte treten, einmal als Instanz einer Java-Klasse mit -Annotation oder aber als -Instanz. Im ersten Fall stellt die Instanz selbst den Wert dar, die  -Instanz hingegen kapselt den Wert in der Eigenschaft . Falls in einer An- wendung diese beiden Formen vermischt und beliebig auftreten, kann der Zugriff auf die Werte über die Methode  vereinheitlicht werden, statt jedes Mal den einen oder anderen Fall zu überprüfen. Hier ein Beispiel für unsere - und -Objekte.    4.1.3 Objekte erzeugen mit der ObjectFactory Wie wir im Übersichtskapitel zur JAXB bereits erwähnt haben, können wir mit einer durch den Schema-Compiler angelegten Klasse -Instanzen der generierten Java Beans erzeugen. Hierzu bietet diese Klasse eine -Methode für jedes Element des zugrunde liegenden XML-Schemas. Für unseren Online-Banking-Service enthält sie z.B. die Methoden  , ,  etc. Ein Beispiel veranschaulicht die Ar- beit mit der .                               77
    • 4 JAXB-API                    In dem ausführbaren Beispiel erzeugen wir eine Instanz der Klasse . Diese nutzen wir, um Objekte für Kunden-, Konto- und Portfolioinformationen zu erzeugen. Die Objekte werden über die Zugriffsmethoden miteinander verbunden und einer Variablen vom Typ  zugewiesen, welche die gesamte Antwort des Online-Banking-Service darstellt. Dieses Objekt können wir nun in ein XML-Dokument transformieren. Elemente vom Typ JAXBElement erzeugen Die oben erzeugten Instanzen vom Typ , ,  etc. stellen die Java-Repräsentation der im XML-Schema definierten Typen dar. Ein XML-Element z.B. vom Typ  kann jedoch zusätzlich Namespace-Informationen besitzen. Diese zu- sätzlichen Namespace-Informationen werden durch den Typ  abgebildet. Daher bietet die  zusätzlich Methoden, die aus einer Java-Repräsentation ein Objekt vom Typ  erzeugen, das den XML-Namen und Namespace- Informationen enthält. Dadurch entfällt ein manuelles Erzeugen von XML-Elementnamen. Die folgende Definition für das Objekt      kann damit durch diesen Aufruf mit der  ersetzt werden.  4.1.4 Zusammenfassung Ein  kann auf verschiedene Arten angelegt werden: unter Angabe von Paketnamen, Klassenobjekten oder eines alternativen Classloaders. 78
    • 4.2 Marshalling Die Hilfsklasse  liefert uns die Information, ob ein gegebenes Ob- jekt per JAXB an XML gebunden ist. Der Schema-Compiler erzeugt automatisch eine Klasse , mit der sich Instanzen der generierten Java Beans und Elementinstanzen vom Typ  erzeugen lassen. 4.2 Marshalling Mit dem im vorigen Abschnitt erzeugten -Objekt kann der Online-Banking- Service nun zur Tat schreiten und die gewünschten Informationen in einem XML- Dokument an den Client senden. Die Informationen über Kunde, Konto und Portfolio wur- den vom Service z.B. aus einer Datenbank bezogen und liegen jetzt als Objekte im Spei- cher vor. Die Transformation dieser Objekte in ein XML-Dokument, die einem vorgegebenen Schema entspricht, wird nun vom  der JAXB-Implementierung übernommen. Der  ist also in der Lage, Java-Objekte, die an XML gebunden sind, in ihre XML-Repräsentation zu überführen. Die Daten, die in unserem Online-Banking-Service vielleicht aus einer Datenbank gelesen wurden, liegen vielleicht noch nicht als XML- gebundene Java-Klassen vor, was dann? Sehen wir uns dazu die zwei möglichen Szenarien einer JAXB-Bindung an: Bindung eines existierenden Datenmodells: Hier wird ein existierendes Java- Datenmodell mit Annotationen manuell an ein XML-Schema gebunden. Ein solches Datenmodell können wir dem  direkt übergeben. Generieren eines Datenmodells aus einem XML-Schema: In diesem Fall werden Java- Klassen eigens aus einem existierenden Schema heraus erzeugt. Um Instanzen dieser Klassen zu erzeugen, generiert der Schema-Compiler die Klasse , die wir weiter oben bereits im Einsatz gesehen haben. 4.2.1 Das Marshaller-Objekt anlegen Über das Kontextobjekt vom Typ  erzeugen wir nun über die entsprechende Factory-Methode ein -Objekt.   Die Schnittstelle  vereint alle API-Methoden, die für den Marshalling-Prozess von Bedeutung sind. Dazu gehören Methoden, die den Marshalling-Prozess starten, die Registrierung von Event-Handlern, das Einschalten der Validierung etc. 79
    • 4 JAXB-API 4.2.2 Den Marshalling-Prozess starten Durch Aufruf von  wird der Marshalling-Prozess gestartet. Diese Methode erwartet zwei Parameter. Der erste Parameter vom Typ  stellt das zu transformierende Java-Objekt dar. Es wird bewusst nur der Typ  erwartet, da die Java-Klassen einfache POJO1s sein können, daher keinerlei Schnittstellen implementie- ren müssen. Die einzige Einschränkung, die hier gilt, ist, dass nur Objekte verarbeitet werden können, die an ein gültiges Wurzelelement eines XML-Schemas gebunden wurden. Dies wird in- tern durch die bereits vorgestellte Methode  der Klasse  überprüft. Ist das übergebene Objekt kein solches Element, wird der Prozess mit einer  abgebrochen. Der zweite Parameter gibt das Ausgabeformat des Marshalling-Prozesses an. Für jedes der möglichen Ausgabeformate gibt es eine eigene Methode. Tabelle 4.2 Marshalling-Ausgabeformate Marshal-Methode Ausgabeformat  Marshalling der Objektstruktur in einen Writer, z.B. einen  zur Ausgabe in einer Datei.  Ausgabe in eine entsprechende Instanz von .  Ausgabe als Ergebnis einer TrAX2 XSLT- Transformation  Ausgabe in eine DOM-Instanz  Ausgabe in einen ContentHandler für SAX2 vents  Ausgabe mit dem XMLStreamWriter der StAX3- API Diese verschiedenen Ausgabeformate können in zwei Gruppen aufgeteilt werden. Mit den Standard-Java-Ausgabeschnittstellen wie  oder  wird der Inhalt „endgültig“ als XML-Dokument serialisiert. Die anderen Formate ermöglichen die Anbin- dung und Weiterverarbeitung der Ausgabe durch Java-XML-APIs wie TrAX oder StAX. So können Inhalte nach dem Marshalling z.B. durch einen Handler für SAX2-Events mo- difiziert werden. Eine komplette (und insbesondere aktuelle) Auflistung der möglichen Ausgabeformate findet sich in der Javadoc-Dokumentation der Klasse . 1 Plain Old Java Object 2 Transformation API for XML 3 Streaming API for XML 80
    • 4.2 Marshalling XML in Datei schreiben Die im Beispiel mit Hilfe der  erzeugten Java-Objekte können wir auf die folgende Weise als XML-Dokument in einer Datei  abspeichern:  XML in ein W3C-DOM-Dokument schreiben Ein W3C-DOM-Dokument kann ebenfalls erzeugt werden. Statt einer Datei wird hier ein Objektbaum aus W3C-DOM-Knoten erzeugt.       XML auf der Konsole ausgeben Sehr nützlich für Test- und Debugging-Zwecke ist die Ausgabe auf der jeweiligen Konso- le. Dies liefert der folgende Aufruf.   XML als StAX XML-Stream ausgeben Hier wird die StAX-API der JAXP verwendet, um einen XML-Ausgabestrom zu erzeugen.     4.2.3 Den Marshalling-Prozess konfigurieren Der Marshalling-Prozess kann durch das Setzen spezieller Parameter über die Methode  konfiguriert werden. Diese Parameter übergeben wir der - Instanz vor dem eigentlichen Marshalling.  Das obige Beispiel veranlasst den  durch Setzen der Property , die XML-Elemente in der Ausgabe entsprechend einzurücken, um ein für Menschen besser lesbares Dokument mit vielen Leer- und Formatierungszei- chen zu erzeugen. Praktischerweise sind für die einzelnen Property-Bezeichner String- Konstanten in der Klasse  vorhanden. 81
    • 4 JAXB-API Wir wollen einen weiteren Parameter vorstellen, nämlich . Diese Eigenschaft weist den  an, den Ort des übergebenen Schemadokuments in der Ausgabe zu deklarieren. Der Ort wird dabei so angegeben, wie er auch im entsprechenden -Attribut eines XML-Dokuments deklariert werden würde, nämlich Namespace URI + URI des Schemadokuments.   Der Umfang der unterstützten Parameter hängt von der jeweiligen Implementierung der JAXB-Spezifikation ab. In der folgenden Tabelle sind die Standard-Properties, die von je- der -Implementierung der JAXB-Spezifikation unterstützt werden sollen, fett abgedruckt. Tabelle 4.3 Marshalling-Properties Property Bedeutung Datentyp jaxb.encoding Zeichensatz des ausgegebenen XML, java.lang.String falls nicht anders angegeben, ist hier  gesetzt. jaxb.formatted.output Gibt an, ob das ausgegebene XML einge- java.lang.Boolean rückt werden soll:  = Ausgabe eingerückt  (Standard) = Ausgabe nicht ein- gerückt jaxb.schemaLocation Durch diese Eigenschaft kann dem aus- java.lang.String gegebenen XML-Dokument der Ort eines XML-Schemas mit dem -Attribut über- geben werden. Diese Eigenschaft gilt für XML-Dokumente, die einen oder mehrere Namespaces verwenden. jaxb.noNamespaceSchema- Diese Eigenschaft übergibt den Ort eines java.lang.String Location Schemadokuments für Dokumente, die keine Namespaces verwenden. Hier wird das gleichnamige Attribut  verwendet. jaxb.fragment Gibt an, ob der Marshaller Events wäh- java.lang.Boolean rend des Marshalling-Prozesses generie- ren soll. Die Standardeinstellung ist dabei . com.sun.xml.bind.character- Mit dieser Eigenschaft kann ein eigener com.sun.xml.bind.marshaller. EscapeHandler Handler zur Konvertierung von Steuerzei- CharaterEscapeHandler (nur JAXB 2.0 RI) chen (Escape Characters) angegeben werden. 82
    • 4.2 Marshalling Property Bedeutung Datentyp com.sun.xml.bind.namespacePrefix Gibt eine Handlerklasse an, die den com.sun.xml.bind.marshalle Mapper Marshaller veranlasst, benutzerdefi-  nierte Präfixe zu generieren. (nur JAXB 2.0 RI) com.sun.xml.bind.indentString Gibt die Zeichenfolge an, die zur Ein- java.lang.String rückung genutzt werden soll, wenn (nur JAXB 2.0 RI) die Eigenschaft jaxb.formatted.output gesetzt ist. com.sun.xml.bind.xmlHeaders Diese Eigenschaft gibt die Präambel, java.lang.String (nur JAXB 2.0 RI) also das Element  im Kopf eines XML-Dokuments, an. Hier können z.B. Kommentare oder -Deklarationen erfolgen. 4.2.4 Das fertige Beispiel Das folgende Codebeispiel zeigt den gesamten Marshalling-Prozess anhand unseres Onli- ne-Banking-Service. Dieser generiert eine Antwort, indem die vorhandenen Objekte in ein XML-Dokument transformiert werden. Das Ergebnis der Transformation wird dann in ei- ner Datei abgespeichert. In einer realen Anwendung würde diese Antwort natürlich nicht als Datei versendet, sondern eher in eine SOAP-Nachricht verpackt werden, um dann als Antwort eines Webservice über die Netzwerkschnittstelle versendet zu werden.                            83
    • 4 JAXB-API                                  Das resultierende XML-Dokument nach Ausführung des oben stehenden Codes sieht dann folgendermaßen aus:                          84
    • 4.2 Marshalling    Das Listing zeigt, dass der  tatsächlich das entsprechende Schema im -Attribut angibt. Die Präfixe der deklarierten Namespaces werden einfach durchnummeriert. 4.2.5 Marshalling beliebiger Objekte Wie oben bereits erwähnt wurde, verarbeitet der  nur solche Java-Objekte, die Wurzelelemente eines XML-Schemas darstellen, also Elemente, die im Schema auf obers- ter Ebene deklariert sind. Ein solches Element ist z.B. das -Element, welches das Wurzelelement in unserem Online-Banking-Service-Schema darstellt. Das Element  dagegen ist kein solches Wurzelelement. Nun wäre es aber auch denkbar, dass wir statt eines -Objekts auch einmal einen einzelnen Kundenda- tensatz vom Typ  transformieren wollen. Für diesen Fall gibt es zwei mögliche Wege. Die Klasse JAXBElement als Wrapper nutzen Eine einfache Möglichkeit, ein solches Marshalling durchzuführen, ist die Benutzung einer Wrapper-Klasse. Verpacken wir ein Kundenobjekt vom Typ  mit der Wrapper- Klasse , kann das Marshalling problemlos durchgeführt werden. Das Verpacken der Objektinstanz übernimmt wieder die Klasse . Dadurch wird aus dem Objekt ein transformierbares Element vom Typ . Die- ses Element enthält neben dem eigentlichen Objekt zusätzliche Informationen wie z.B. den Elementnamen und Namespace-Informationen. Im Programmcode sieht das folgenderma- ßen aus:                       85
    • 4 JAXB-API                         Die Annotation @XmlRootElement verwenden Falls wir ein bestehendes Java-Datenmodell an ein XML-Schema binden, können wir den Typ  zu einem Wurzelelement machen, indem wir die Klasse  mit der Annotation  versehen. Die Klasse wird dadurch automatisch als JAXB- Element erkannt. Die nötigen Namespace-Informationen sind hier bereits in der Annotati- on enthalten. Dadurch wird ein direktes Marshalling ohne den Umweg über eine Wrapper- Klasse möglich. Hinweis Ein Objektgraph muss nicht zwingend konform zu einem Schema sein, um mit dem   verarbeitet werden zu können. Der  ist daher in der Lage, auch un- gültige Inhalte in ein XML-Dokument zu überführen. 4.2.6 Zusammenfassung Mit dem  lassen sich Java-Objekte in XML-Strukturen transformieren. Eine -Instanz wird über den  angelegt. Der  kann Java-Objekte in verschiedene Ausgabeformate transformieren, darunter Standardschnittstellen wie Dateien oder Streams, aber auch Ausgabeformate anderer XML-APIs wie DOM, StAX oder TrAX. Durch das Setzen von Properties können wir Einfluss nehmen auf den Marshalling- Prozess. 86
    • 4.3 Unmarshalling Es können prinzipiell beliebige Objekte transformiert werden, auch einem XML- Schema nach ungültige XML-Inhalte. 4.3 Unmarshalling Bisher hat unser Online-Banking-Service eine XML-Antwort unter Verwendung von  und  erstellt und an einen Client versendet. Wie können wir nun dieses XML-Dokument in der Clientanwendung verarbeiten? Das Zauberwort heißt hier Unmarshalling. Wir wissen bereits, dass beim Unmarshalling XML-Elemente in einen Graph aus Java-Objekten im Speicher transformiert werden. Die XML-Elemente können dabei ein ganzes Dokument darstellen oder auch nur einen Teil davon. Wichtig ist, dass die Elemente in einem Schema definiert wurden, das dem  vorher bekannt ge- macht wurde. Bei Elementen sollten wir dabei zwischen global und lokal definierten Ele- menten unterscheiden. Globale Elemente und Datentypen (-/) sind in einem Schema auf der obersten Ebene definiert. Der  kennt für jedes globale Element, Da- tentypen ausgenommen, eine Abbildung auf eine Java-Klasse. Ein XML-Dokument mit einem global definierten Wurzelelement an den  zu übergeben, ist wohl der Standardfall. Der  kann solche XML-Dokumente ohne Umwege transformieren. Ein Beispiel für ein globales Element in unserem Schema ist das  -Element. Ein global definierter Datentyp ist z.B. der Datentyp , der im Kundenschema auf oberster Ebene definiert ist. Lokale Elemente werden innerhalb einer anderen Elementdeklaration definiert. Ein XML-Dokument, das ein lokales Element als Wurzelelement besitzt, kann der   nicht mit dem Standardweg über den  auf die korrekte Klasse ab- bilden. Wie das Unmarshalling solcher Teildokumente funktioniert, wird in Abschnitt 4.3.7 näher beschrieben. 4.3.1 Das Unmarshaller-Objekt anlegen Zunächst sehen wir uns den Standardfall an, in dem wir ein global definiertes Element als Wurzel eines XML-Dokuments transformieren. Der Unmarshaller der JAXB- Implementierung verwendet eine -Instanz, um dieses Wurzelelement der richtigen Java-Klasse zuzuordnen. Als Erstes müssen wir daher wieder einen solchen Kon- text erzeugen. Analog zum Marshalling kann dann mit Hilfe des Kontexts ein Service- Objekt vom Typ  erzeugt werden. Die Methode  des  liefert uns eine Implementierung des Interface Unmarshaller zurück.   87
    • 4 JAXB-API 4.3.2 Den Unmarshalling-Prozess starten Die Java-Schnittstelle  bietet uns jetzt analog zu  einige  -Methoden, die das Unmarshalling eines XML-Dokuments durchführen. Die möglichen Eingabeformate entsprechen dabei der Auswahl von Ausgabeformaten beim Marshalling. Eine Ausnahme bildet hier die -Variante, die eine Adresse vom Typ  als Parameter aufnimmt. Als Rückgabe liefern alle Methoden ein Ob- jekt vom Typ . Abhängig von dem gelesenen XML-Dokument kann die Methode beliebige Java-Objekte zurückgeben. Tabelle 4.4 Unmarshalling-Eingabeformate Unmarshal-Methode Eingabeformat  Unmarshalling eines XML-Dokuments im Java-Dateiformat   Angabe einer Dokumentadresse vom Typ   Übergabe eines Eingabestroms, z.B. einer XML-Datei  Übergabe einer Transformationsquelle der TrAX4-API  Ausgabe als DOM-Parsebaum  Übergabe einer SAX-konformen Ein- gabequelle  Übergabe eines XMLStreamReaders der StAX5-API  Ausgabe eines XMLEventReaders der StAX-API Die Eingabeformate unterscheiden sich ebenfalls wieder in die Standard-Java- Eingabeformate wie  oder  und Eingabeformaten, welche die Integrati- on von JAXB mit anderen XML-APIs erlauben. Als Beispiel für die Anwendung der -Methode lesen wir im folgenden Quell- textauszug das XML-Dokument ein, das wir im letzten Abschnitt mit dem Marshaller er- zeugt haben.   4 Transformation API for XML 5 Streaming API for XML 88
    • 4.3 Unmarshalling Der  benutzt den , um das Wurzelelement  auf die Klasse  abzubilden, und liefert uns daher ein Objekt vom Typ  zurück, das genau die Antwort des Online-Banking-Service darstellt und mit dem wir jetzt in unse- rer Clientanwendung weiterarbeiten können. 4.3.3 Den Unmarshalling-Prozess konfigurieren Im Gegensatz zum  sieht die JAXB-Spezifikation 2.0 keine besonderen Para- meter vor, die für den Unmarshalling-Prozess gesetzt werden können. Auch die einzelnen JAXB-Implementierungen bieten hier bisher keine implementierungsspezifischen Eigen- schaften an. 4.3.4 Das fertige Beispiel Hier noch einmal eine komplette Methode, die das Unmarshalling unseres - Dokuments durchführt. Der  wird in diesem Beispiel zur Anschaulichkeit innerhalb des Methodenrumpfes neu erzeugt. In einer realen Anwendung sollte ein bereits bestehender Kontext aus Performancegründen in die Methode hereingereicht werden. Der  nutzt die im  bekannte Abbildung des -Elementes auf die Java-Klasse , um den korrekten Datentyp zurückzuliefern.                          89
    • 4 JAXB-API 4.3.5 Das xsi:type-Attribut beim Unmarshalling verwenden Angenommen, wir bekommen jetzt aus einer unbekannten Quelle ein XML-Dokument mit einem anderen Wurzelelement. Als Basis besitzt es zwar die Struktur des Elements  , es beinhaltet jedoch noch ein zusätzliches Unterelement und heißt auch noch an- ders ...              Nun wollen wir in der Lage sein, ein solches Dokument trotzdem in ein -Objekt zu transformieren. Der Datentyp  muss dazu im Schema allerdings wie folgt glo- bal definiert sein.         Mit dem -Attribut können wir mit Schemamitteln einem Parser den Tipp geben, dass ein Element A vom Typ her einem Element B entspricht. Dieses Attribut wird auch vom Unmarshaller beachtet. Findet der  nämlich keinen passenden Typen für den Namen des Wurzelelements, so versucht er, bei Angabe eines -Attributs den dort spezifizierten Typen im  zu finden. Die Lösung unseres Problems wäre daher, in unserem XML-Dokument eine Typsubstitution mit  vorzuneh- men.          Der Aufruf für das Unmarshalling eines solchen Dokumentes ist jetzt der folgende: 90
    • 4.3 Unmarshalling                        Aufgrund der Typsubstitution bekommen wir hier ein Objekt vom Typ  zu- rück. Mit der Methode  erhalten wir schließlich das an Java gebundene XML- Element in Form einer -Instanz. Hier können wir alle Werte des Datentyps   verarbeiten, ausgenommen davon allerdings das zusätzliche Element  . 4.3.6 Elemente ohne @XMLRootElement verarbeiten Das eingangs mit dem  verarbeitete Dokument besitzt ein - Element als Dokumentwurzel. Die zu diesem Element gehörige JAXB-Klasse  besitzt eine  Annotation. Daher konnten wir das Ergebnis des Unmars- hallers direkt an ein Objekt vom Typ zuweisen. Das -Element unseres Schemas hingegen ist nicht als globales Element im Schema definiert. Es wird innerhalb des -Elementes definiert. Seine Definition verweist auf den komplexen Datentyp , der wiederum aus dem Kundenschema importiert wurde. Wie können wir jetzt trotzdem ein XML-Dokument einlesen, das den folgenden Kunden- datensatz im Element  als Wurzelelement enthält?              91
    • 4 JAXB-API Das Element  ist dem  aus dem importierten Kunden- schema als globales Element bekannt. Der Datentyp dieses Elements ist vom Typ  . Eigentlich sollten wir erwarten, dass wir beim Unmarshalling dieses Elements ein Objekt vom Typ  erhalten. Solange nun das Element  das einzige Element vom Typ  ist, wäre dieses Verhalten stets eindeutig. Fänden wir in einer Methode ein Java-Objekt vom Typ Customer, so könnten wir sicher zur Aussage kommen, dass es sich hierbei um eine Instanz des XML-Elements  handelt. Sobald jedoch mehrere solcher Elemente im Dokument vorkommen dürfen, bspw. gleich- zeitig als  und als , wie können wir (bzw. später der Marshal- ler) diese auseinanderhalten? Wir müssen solche Elemente daher mit der Information ver- sehen, an welcher Stelle im Dokument diese stehen. Für diesen Fall bietet die JAXB-API die Klasse , mit der die Instanz eines reinen Java-Objektes mit den XML-spezifischen Informationen zu Elementname und Na- mespace versehen werden kann. Zurück zu unserem Beispiel: Die Java-Klasse  definiert keine -Annotation, es handelt sich dabei also um eine Java-Klasse, die an ei- nen XML-Typ, aber nicht an ein Wurzelelement gebunden ist. Beim Unmarshalling dieses Dokuments bekommen wir daher kein Objekt vom Typ  zurück, sondern ein Ob- jekt vom Typ . Dieses Objekt stellt nun ein XML-Element vom Typ  dar, was ja für das Element  aus unserem Beispiel zutrifft. Mit der Methode  können wir nun auf das -Objekt zugreifen, das die Werte des Elements und seiner Unterele- mente kapselt. Im folgenden Beispiel lesen wir nun das Element  ein und überprüfen den Namen des Kunden:                      92
    • 4.3 Unmarshalling      Von der Variablen  könnten wir nun beispielsweise den Namen des Elements abfragen („customerElement“) oder in welchem Namespace dieses Element definiert ist. Diese Informationen sind in der Variablen  nicht mehr verfügbar, hier haben wir nur noch die reinen Werte des Elements. 4.3.7 Unmarshalling von Teilen eines XML-Dokuments Wir haben gelernt, dass lokal definierte Elemente unseres -Schemas im  , also Teile eines XML-Dokuments, nicht ohne weiteres mit dem Unmarshaller eingelesen werden können. Auf die Formulierung „ohne weiteres“ gehen wir im Folgenden näher ein. Betrachten wir hierzu die folgenden -Methoden, die wir bisher haben links liegen lassen:     Diese Methoden arbeiten wieder mit den bekannten Eingabeformaten, in denen das Doku- mentfragment übergeben werden kann. Zusätzlich zum XML-Teildokument übergeben wir dem  eine Java-Klasse als -Instanz. Diese Java-Klasse definiert für den Unmarshaller den Typ, in den das Teildokument eingelesen werden soll. Der Unmars- haller versucht dann, das Teildokument auf die Struktur der angegebenen Klasse abzubil- den. Dies ermöglicht uns z.B., nur den Ausschnitt des Elements  innerhalb eines -Dokuments auszulesen:                       93
    • 4 JAXB-API Im folgenden, ausführbaren Beispiel erzeugen wir zuerst ein W3C-DOM-Dokument vom Typ  aus dem oben angegebenen XML-Dokument. Innerhalb dieses - Objekts selektieren wird den DOM-Knoten, der dem Element  entspricht. Dieses erfolgt in dem Beispiel mittels der XPath-API. Nachdem wir nun den entsprechenden Kno- ten in Form eines -Objektes als Teildokument isoliert haben, übergeben wir dieses der entsprechenden -Methode zusammen mit dem Tipp, dass wir uns eine Instanz von  aus dem Unmarshalling erhoffen. Der Aufruf dieser Methode liefert uns ein Objekt vom Typ  zurück.                                           Das aus dem Unmarshalling resultierende  kapselt eine Instanz der Klasse , die wir mit der Methode  abfragen können. Die Ausgabe des Kindele- 94
    • 4.3 Unmarshalling ments  sollte nun die Stadt  als Ausgabe liefern – wir haben erfolgreich ein Teildokument eingelesen. Hinweis Dieses explizite Unmarshalling überschreibt eine evtl. vorhandene Abbildung auf eine Java- Klasse im . Es wird dann auf jeden Fall versucht, zunächst ein Unmarshalling auf die als Parameter angegebene Klasse durchzuführen. Wurde jedoch für das XML-Element ein xsi:type-Attribut angegeben, hat dieses Attribut Vorrang vor allen anderen Bindungen. Die Reihenfolge der Bindung ist hier also: 1. Wert des -Attributs 2. Falls angegeben, der -Parameter der -Methode 3. Bekannte Abbildung im  4.3.8 Flexibles Unmarshalling nutzen In der JAXB-Übersicht wurden bereits die zwei Konzepte Structural Unmarshalling und Flexible Unmarshalling erläutert. Hier wollen wir uns ein konkretes Beispiel für die fle- xible Behandlung von unbekannten XML-Inhalten ansehen. Stellen wir uns vor, dass das XML-Schema unserer Beispielanwendung weiterentwickelt wurde. Man spricht hier auch gerne von Schemaevolution. Sehen wir uns dazu noch einmal das Teilschema zu unserem -Element an, das die Wertpapierdaten unseres Kunden enthält. Der Datentyp  ist folgendermaßen definiert.            Die zugehörige Java-Klasse mit Annotationen sieht folgendermaßen aus:           Die Toleranz des Unmarshallers nutzen Obwohl hier für das Element  eine  mit definierter Reihenfolge vor- gegeben ist, ist es dem  zunächst recht einerlei, in welcher Reihenfolge die 95
    • 4 JAXB-API Elemente auftauchen. Wir können z.B. auch ein solches -Element problemlos verarbeiten:                         Die Reihenfolge im obigen Beispiel stimmt nicht ganz mit dem Schema überein, das Ele- ment  befindet sich an der falschen Stelle. Während die Schemavalidierung hier allerlei Fehler ausgibt, wird dieses Dokument dennoch korrekt verarbeitet. Aber hier gibt es noch etwas wesentlich Interessanteres zu entdecken. Wie bereits erwähnt, hat sich das Schema weiterentwickelt. Und zwar ist in diesem Element ein weiterer Wert- papiertyp  hinzugekommen, der Renten und Anleihen mit den zugehörigen Daten ab- bildet. Der Unmarshaller ignoriert unbekannte Elemente einfach. Auf diese Weise können prinzi- piell auch ältere Versionen der Anwendung mit geänderten XML-Dokumenten arbeiten. Der Aufruf des Unmarshallers ist weiterhin gleich geblieben. Das Element any für unbekannte Elemente nutzen Es könnte auch sein, dass wir beim Entwickeln des -Schemas bereits wissen, dass ein neuer Wertpapiertyp, wie etwa Anleihen, hinzukommen könnte. Wir könnten dies in der -Definition durch ein -Element ausdrücken.             96
    • 4.4 Validierung Die zugehörige Java-Klasse besitzt nun zusätzlich eine Liste  vom Typ , die be- liebige Objekte aufnehmen kann.            Führen wir jetzt das Unmarshalling durch, enthält die Liste  das Element  als In- stanz von  mit unserem Anleihepapier, das im vorigen Durchlauf noch ignoriert wurde. Wir könnten sogar probeweise versuchen, dieses unbekannte Ele- ment durch den Unmarshaller in einen der bekannten Datentypen umzuwandeln. Auf diese Weise lassen sich also erweiterbare Anwendungen bauen, die auch unbekannte Elemente oder Dokumente mit variierenden Inhalten verarbeiten können. 4.3.9 Zusammenfassung Mit dem  lassen sich XML-Dokumente in Java-Objektgraphen trans- formieren. Eine -Instanz wird über  angelegt. Der  versteht mehrere Eingabeformate, aus denen er Java-Objekte er- zeugen kann. Es können Dateien, Datenströme, aber auch Formate anderer XML-APIs verarbeitet werden. Momentan existieren für den  keine speziellen Konfigurationsmöglich- keiten. Neben vollständigen XML-Dokumenten, die einem Schemawurzelelement entspre- chen, können mit  auch Teildokumente verarbeitet werden, solange die- se noch als XML gelesen werden können. Durch die Angabe eines Datentypen mit  kann mit Schemamitteln ein Ele- ment auf ein anderes abgebildet werden. Objekte, deren Klasse eine  Annotation besitzt, können direkt ge- schrieben und gelesen werden, alle anderen werden in -Instanzen ver- packt. Das ist am Anfang etwas verwirrend. 4.4 Validierung Aus der JAXB-Übersicht wissen wir bereits, dass sowohl beim Marshalling als auch beim Unmarshalling eine Validierung der XML-Dokumente gegen ein XML-Schemadokument 97
    • 4 JAXB-API durchgeführt werden kann. Diese Validierung ist optional und kann je nach Anwendungs- fall eingesetzt oder weggelassen werden. Mit der JAXB-Version 2.0 wurde die bisherige Validierung vollkommen umgestellt. Die neue Version 2.0 nutzt die bereits existierende Validierungs-API der JAXP 1.3. Die JAXP 1.3 ist Teil der JSE 5, daher bietet es sich an, diese bestehende API zu nutzen statt eine zu- sätzliche Implementierung einer Schemavalidierung innerhalb JAXB bereitzustellen. Die Validierungs-API der JAXP ist im Paket  zusammengefasst. Wie die Validierung konkret funktioniert, werden wir im Folgenden näher erläutern. 4.4.1 Beim Unmarshalling validieren Damit wir sicherstellen können, dass die Antwort, die wir von unserem Online-Banking- Service bekommen, auch einen gültigen Datensatz darstellt, wollen wir eingehende XML- Dokumente beim Unmarshalling validieren. Dazu sind die folgenden Schritte notwendig. Als Erstes definieren wir, mit welchem XML-Schema das Dokument validiert werden soll. Im Rahmen der Validierungs-API legen wir dieses als Schemaobjekt an, das eine Referenz auf dieses Schema darstellt und in dem die Validierungslogik für das spezielle Schema ge- kapselt ist. Ein solches Objekt vom Typ  erzeugt die  der JAXP 1.3 auf die folgende Weise:    Wir besorgen uns zunächst eine Instanz der . Mit Hilfe der   können wir dann ein neues -Objekt erzeugen. Dabei übergeben wir das XML- Schemadokument als Parameter an die Methode . Dieses -Objekt registrieren wir nun an der -Instanz mit der Methode . Falls ein solches -Objekt beim  registriert wurde, wird automatisch eine Validierung während des Unmarshallings durchgeführt. Hier noch einmal ein komplettes Beispiel:                98
    • 4.4 Validierung                         Im obigen Beispiel führen wir das Unmarshalling zweimal durch, einmal mit einem gülti- gen Dokument  und einmal mit einem ungültigen Dokument  . Im letzteren Dokument haben wir das Geburtsdatum unseres Kunden im Element  auf den Wert  gesetzt. Da der Februar maximal 29 Tage besitzt, stellt diese Angabe ein ungültiges Datum dar. Das Unmarshalling des ersten Dokuments sollte fehlerfrei verlaufen. Tritt jetzt während des Unmarshalling-Prozesses des zweiten Dokuments ein Validierungsfehler auf, d.h., ver- stößt der Inhalt des XML-Dokuments gegen das registrierte Schema, so wird das Unmars- halling mit der Ausnahme  abgebrochen. Die -Methode wirft dabei standardmäßig eine , die wiederum eine Oberklasse der  darstellt. Die Ausgabe des obigen Beispiels ist daher folgende.     Die fehlerhafte Angabe wurde nun rechtzeitig entdeckt, bevor durch das ungültige Datum Folgefehler in unserer Anwendung entstehen können. 4.4.2 Beim Marshalling validieren Auch beim Marshalling kann eine Validierung durchgeführt werden. Der Aufruf im Java- Code ist analog zum obigen Beispiel mit der Ausnahme, dass die -Methode entsprechend auf dem -Objekt aufgerufen wird. Nun wird vor der Umwand- 99
    • 4 JAXB-API lung in XML eine Validierung der Daten im Java-Objektgraph durchgeführt. Verstößt der Inhalt der Objekte im Speicher gegen die Einschränkungen des XML-Schemas, wird der Marshalling-Prozess durch eine Ausnahme abgebrochen.                                                        100
    • 4.4 Validierung          Wenn wir das obige Beispiel ausführen, wird das Marshalling mit folgender Fehlermel- dung abgebrochen:       Aus der Fehlermeldung können wir erkennen, dass für den Typ  eine  -Einschränkung vorliegt. Der angegebene Wert  ist also zu hoch. Daher wird eine entsprechende  geworfen. Nach Ändern des Wertes für  im Java-Code werden wir sehen, dass das Marshalling ein einwand- freies, schemakonformes XML-Dokument erzeugt. Hinweis Die Validierung beim Marshalling ist neu seit der JAXB-Version 2.0. Sie wurde vor allem mit Rücksicht auf die Unterstützung von Webservices hinzugefügt. Ein Webservice versendet Da- ten typischerweise im XML-Format. Diese Daten müssen dabei konform zu einem WSDL- Dokument sein, das wiederum mehrere XML-Schemas einbindet. JAXB dient dabei als mög- lichst transparente Bindung zwischen den Java-Objekten und den im Rahmen des Webservice- Aufrufs übermittelten XML-Dokumenten. Durch die Validierung während des Marshallings kann sichergestellt werden, dass nur XML-Dokumente übermittelt werden, die der WSDL- Beschreibung genügen. 4.4.3 Benutzerdefinierte Validierung Bisher haben wir uns nicht weiter um die Konfiguration der Validierung gekümmert. Wir haben einfach ein Schema angegeben, anhand dessen die jeweiligen Daten validiert wer- den sollten. Wie JAXB dabei auf Fehler reagiert, haben wir dabei völlig der JAXB- Referenzimplementierung überlassen. Diese hat daher eine Standardfehlerbehandlung verwendet, die einfach nach dem Auftreten des ersten Fehlers das Marshalling bzw. Un- marshalling abbricht. Ein Ereignis bei der Validierung, wie z.B. ein Fehler, wird in JAXB durch ein Objekt vom Typ  repräsentiert. Dieses Objekt enthält alle wichtigen Informationen zu einem Validierungsereignis. Wir können diese Ereignisse auch manuell verarbeiten und programmatisch entscheiden, wann welche Ausnahme auftreten oder wie auf Validierungs- fehler reagiert werden soll. 101
    • 4 JAXB-API Hier der Aufbau der Klasse :          Die Schnittstelle bietet uns vier verschiedene Eigenschaften eines Ereignisses, die über die entsprechenden Getter-Methoden abgerufen werden können. : Diese Eigenschaft gibt den Schweregrad des Ereignisses an. Die W3C- XML-Spezifikation definiert dabei drei Arten von Ereignissen. Beim Typ  handelt es sich um unkritische Fehler im XML-Dokument, die nicht zum Abbruch der Verarbeitung führen müssen. Die Typen  und  unterscheiden sich dadurch, dass nach einem Fehler vom Typ  die Verarbeitung, d.h. das Marshalling bzw. Unmarshalling, abgebrochen werden muss. Wird die Verarbeitung nach einem  nicht abgebrochen, ist das Verhalten des  oder  undefiniert. : Mit dieser Eigenschaft erhalten wir die Fehlermeldung der Validierung in natürlichsprachlicher Form. : Der Aufruf dieser Methode liefert die mit dem Ereignis ver- knüpfte Fehlermeldung. : Mit Hilfe dieser Methode bekommen wir nähere Informationen über den Ort, an dem der Fehler aufgetreten ist. Das zurückgegebene Objekt vom Typ   enthält Eigenschaften, die je nach Art der Validierung gefüllt sind. Tritt der Fehler z.B. beim Marshalling auf, so erhalten wir Informationen über das Ja- va-Objekt, bei dem der Fehler auftrat. Im Rahmen des Unmarshallings liefert das Ob- jekt uns den Ort des XML-Dokuments sowie Zeilen und Spaltennummer des ungülti- gen XML-Elements. Um diese Ereignisse zu verarbeiten, können wir die Schnittstelle   implementieren. Die oben genannte Standardfehlerbehandlung der JAXB wird von der Klasse   übernommen, die eine einfache Implementierung von   zur Verfügung stellt. Treten Ereignisse der Kategorie  auf, gibt  diese auf der Konsole aus. Beim Auftreten des ersten Fehlers ( oder ) hingegen wird die weitere Verarbeitung abgebrochen. Fehler der Kategorie  werden dabei als  weitergeleitet, so dass die Verarbeitung in jedem Fall abbricht. Nun gibt es aber durchaus Szenarien, in denen flexibler auf Fehler reagiert werden muss. In unserem Online-Banking-Service möchten wir vielleicht etwas fehlertoleranter sein. 102
    • 4.4 Validierung Warnungen und unkritische Fehler sollen nur mit der entsprechenden Zeilen- und Spalten- angabe ausgegeben werden, jedoch nicht gleich zu einem nutzerunfreundlichen Pro- grammabbruch führen. JAXB bietet uns dazu zwei verschiedene Möglichkeiten, individuell auf   zu reagieren: Definition einer eigenen Fehlerbehandlung durch Implementierung des Interface  . Die Methode  wird für je- den  aufgerufen und kann mit einer benutzerdefinierten Implemen- tierung gefüllt werden. die Hilfsklasse  benutzen. Diese Klasse sammelt alle , die bei der Validierung auftreten, in einer Liste. Diese Liste kann nach der Validierung von der Anwendung verarbeitet werden. 4.4.3.1 ValidationEventHandler implementieren Schauen wir uns an einem praktischen Beispiel an, wie die Implementierung einer eigenen Fehlerbehandlung funktioniert. Das folgende Listing zeigt eine Klasse  , die für jeden Fehler der Kategorie  den Ort des fehlerhaften Elements im XML-Dokument sowie die Fehlermeldung selbst ausgibt. Im Unterschied zur Standardfehlerbehandlung bricht sie jedoch für einen Fehler der Kate- gorie  nicht ab. Um den Ort des aufgetretenen Fehlers herauszubekommen, greifen wir dabei auf die Klasse  zurück, die Methoden zur Lokalisie- rung der Fehler innerhalb der XML-Dokumente bietet.                           103
    • 4 JAXB-API                 Ein auftretendes Ereignis vom Typ  wird also an die Methode   übergeben, die unsere benutzerdefinierte Logik enthält. Eine -Anweisung prüft zuerst die Kategorie des . Für die Kategorien  und  wird der Wert  in der Methode  zurückgegeben. Dadurch wird der auf- rufende Prozess, in diesem Fall der , dazu veranlasst, das Unmarshalling fortzusetzen. Auf diese Weise kann ein Dokument trotz Fehlern weiter transformiert werden. Tritt je- doch ein Ereignis der Kategorie  ein, wird der Wert  zurückgegeben und die Verarbeitung des Dokuments abgebrochen. Ein Abbruch erfolgt ebenfalls, wenn innerhalb der Methode  eine unbehandelte Ausnahme („unchecked excepti- on“) geworfen wird. Liefern wir im Fall eines Ereignisses vom Typ   zurück, kann alles passieren, aber nur selten etwas Sinnvolles. Der so implementierte  kann mittels der Methode   beim  bzw.  registriert werden. Zu beachten ist noch, dass hier der Aufruf von  weggelassen wurde, da sonst zusätzlich die Standardfehlerbehandlung greift. Diese würde das Unmarshalling dann aufgrund des Feh- lers abbrechen. Ein kompletter Aufruf am Beispiel des Unmarshallers sieht folgenderma- ßen aus.                   104
    • 4.4 Validierung           Wenn wir hier im XML-Dokument wieder das Geburtsdatum unseres Kunden im Element  auf den unseligen Wert  setzen, bekommen wir folgende Meldung von unserem selbst implementierten .    Der Unmarshalling-Prozess läuft jetzt reibungslos bis zum Ende. Außerdem liefert der e- ben definierte  uns jetzt zusätzlich zu einer Fehlermeldung den genauen Ort des Fehlers im aktuell verarbeiteten XML-Dokument. Das hier am Beispiel des -Objekts gezeigte Vorgehen kann natürlich auch analog mit dem  durchgeführt werden. Hinweis Einige Dinge sollten bei der Verwendung eines eigenen  be- achtet werden, um inkonsistente Zustände zu vermeiden. 1. Unbedingte Rückgabe des Wertes  bei Fehlern der Kategorie  2. Der Java-Objektgraph sollte von einem  nicht verändert werden, da dieses ebenfalls zu allerlei unerwarteten Nebeneffekten führen kann. 4.4.3.2 Die Hilfsklasse ValidationEventCollector verwenden Das vorangegangene Beispiel hat gezeigt, wie wir auf Fehler während des Unmarshallings bzw. Marshallings direkt reagieren können. Denkbar wäre aber auch, dass wir nicht sofort auf auftretende Fehler reagieren wollen, sondern erst im Anschluss an die Validierung, wenn das Un-/Marshalling also abgeschlossen ist. So können wir z.B. Fehler über mehrere Aufrufe des Un-/Marshallings hinweg in einer Log-Datei sammeln. Hierzu existiert in JAXB eine Hilfsklasse, die uns das Sammeln von  bereits abnimmt. Die Klasse  im Paket  erfüllt genau diese Funktion. Da diese Klasse ebenfalls die Schnittstelle  implementiert, können wir sie ganz normal mit der Methode  beim  oder  anmelden. Nach erfolgreichem Un-/Marshalling können die aufgetretenen 105
    • 4 JAXB-API Ereignisse dann über die Methode  abgerufen werden. Diese Methode liefert ein Feld von Objekten des Typs  zurück. Die Verwendung des  zeigt das folgende Listing am Beispiel des Unmarshallings.                                             Für dieses Beispiel setzen wir nicht nur ein falsches Geburtsdatum für den Kunden, son- dern auch eine Postleitzahl, die neben Ziffern auch Buchstaben enthält.        106
    • 4.5 Callback-Mechanismen einsetzen     Auf diese Weise erhalten wir die folgenden zwei -Instanzen, nachdem das Unmarshalling durchgeführt wurde.          Diese können wir nun für Fehler- oder Log-Ausgaben weiter aufbereiten. 4.4.4 Zusammenfassung Es können in JAXB sowohl XML-Dokumente als auch Java-Objektgraphen anhand eines XML-Schemas validiert werden. Die Validierung wird einheitlich bei Marshal- ling und Unmarshalling verwendet. Die Validierung wurde mit der JAXB 2.0 komplett überarbeitet und verwendet beste- hende Funktionalität aus der JAXP 1.3. Die Validierung wurde flexibler gestaltet. Die Behandlung von Fehlern kann mit einer Implementierung von  auf spezielle Anwendungsbedürfnis- se zugeschnitten werden. Die Validierung ist ausdrücklich optional gestaltet, sie kann z.B. aus Performancegrün- den deaktiviert werden. Ungültige Inhalte können in der Regel trotzdem verarbeitet werden. 4.5 Callback-Mechanismen einsetzen Dieser Abschnitt wird sich mit den in der JAXB-Übersicht beschriebenen Callback- Mechanismen beschäftigen. Callback-Mechanismen erfreuen sich seit längerer Zeit großer Beliebtheit in vielen Java-Frameworks. So gibt es in vielen APIs und Frameworks sog. Listener, die das Einklinken von benutzerdefiniertem Code möglich macht. Auch JAXB macht hier keine Ausnahme. Es bietet im Wesentlichen zwei Mechanismen, über die eine JAXB-Implementierung benutzerdefinierten Code einbinden kann. Mit die- sen Callback-Mechanismen kann der Entwickler die generierten Klassen mit applikations- spezifischer Logik anreichern, die dann während des Marshallings oder Unmarshallings ausgeführt wird. 107
    • 4 JAXB-API Bei der ersten Variante wird der Code zentral in einer externen -Klasse definiert, während bei der zweiten Variante der Code direkt in den generierten Klassen abgelegt wird. 4.5.1 Die Listener-Klasse verwenden Die JAXB-API stellt sowohl für das Marshalling als auch das Unmarshalling eine abstrak- te -Klasse bereit. Diese Klassen sind jeweils als abstrakte, statische Klassen in- nerhalb der Interfaces  und  definiert. Sie definieren jeweils zwei Methoden, die von einer konkreten Implementierung über- schrieben werden können. Es wurden hier bewusst keine Schnittstellen definiert, da durch die abstrakten Klassen wahlweise nur eine der beiden Methoden implementiert werden kann, während die andere leer bleibt.               Anhand der Namen der Methoden können wir leicht erraten, wann JAXB diese Methoden beim Marshalling bzw. Unmarshalling aufrufen wird. Beim Unmarshalling werden dabei jeweils das aktuell verarbeitete Element sowie das übergeordnete Element, an welches das aktuelle angehängt wird, übergeben. Beim Aufruf von  ist das Objekt  leer, bei  sind alle Eigenschaften außer solche vom Typ  befüllt. Beim Marshalling wird den Methoden jeweils nur das aktuell zu verarbeitende Objekt bergeben. Die einzige Besonderheit ist hier, dass die Methode  erst aufgeru- fen wird, wenn auch das Marshalling aller Kindelemente des betreffenden Knotens beendet ist. Nach dieser allgemeinen Übersicht über die -Klassen wollen wir uns ein konkre- tes Beispiel anschauen. Beispielsweise möchten wir alle Kunden speichern, über die wir Informationen von unserem Online-Banking-Service beziehen. Dazu erstellen wir uns eine eigene -Implementierung für das Unmarshalling. Die folgende Klasse leitet daher von der Klasse  ab und speichert alle Kundendaten, die beim Unmarshalling auftreten, in einer Liste. 108
    • 4.5 Callback-Mechanismen einsetzen                          Wir prüfen also, ob das aktuelle Element vom Typ  ist. Falls ja, wird der Kun- dendatensatz in einer Liste gespeichert. Aber wie binden wir den  jetzt in den Unmarshalling-Prozess ein? Ganz einfach, indem wir unsere frisch definierte Klasse beim -Objekt mit  registrieren.                         109
    • 4 JAXB-API       4.5.2 Callback-Methoden auf Klassenebene definieren Die Definition einer eigenen -Implementierung stellt eine recht allgemeine Me- thode dar, um einen Callback-Mechanismus zu implementieren. Wir können aber ähnliche Methoden wie bei der -Klasse für einzelne Java-Klassen definieren. Damit ist es möglich, auf Klassenebene einzelne Elemente zu modifizieren. Diesen Mechanismus setzen wir ein, wenn wir z.B. auf  deklarierte Attribute und Felder einer mit JAXB gebundenen Java Bean zugreifen möchten. Zum Beispiel können wir Default-Werte spezifizieren, falls Elemente nicht befüllt werden. Das folgende Listing zeigt, wie diese Callback-Methoden definiert werden.                                 Die entsprechenden Methoden für den  lauten wie folgt. 110
    • 4.5 Callback-Mechanismen einsetzen       Implementiert eine Klasse diese Methoden, so werden sie durch den Marshaller bzw. Un- marshaller stets aufgerufen. Benutzerdefinierter Code und generierte Klassen Eine Sache gibt es hier jedoch zu bedenken. Wurde die Klasse  aus einem beste- henden Schema generiert, so werden die eingefügten Methoden bei der nächsten Generie- rung schlicht und einfach überschrieben. Um dies zu verhindern, können wir den Schema-Compiler anweisen, alle generierten Att- ribute und Methoden einer Klasse mit der Annotation  zu versehen. Später werden dann nur solche Elemente bei einer erneuten Generierung überschrieben, die diese Annotation besitzen. Benutzerdefinierte Methoden, wie etwa  und , bleiben dann auch nach dem erneuten Generieren der Klasse erhalten. Dem -Task übergeben wir dazu folgenden Parameter:       Nach erneuter Generierung ist jeder Klassen-, Variablen- und Methodendefinition eine Annotation vorgeschaltet, die in etwa so aussieht:      Diese Annotation ist im JSR 250 „Common Annotations“ definiert. Die entsprechende JAR-Bibiliothek für die Common Annotations ist leider nicht im Umfang der JAXB- Referenzimplementierung enthalten. Die Codebasis zu JSR 250 wird aber in einem Projekt mit dem vielversprechenden Titel Pitchfork verwaltet und ist auf den Seiten der Spring- Entwickler Interface 21 erhältlich. Die URL ist http://www.interface21.com/pitchfork/. Hinweis Die beschriebene Funktionalität wird momentan in der JAXB-Referenzimplementierung noch nicht spezifikationsgemäß umgesetzt. Die Methoden werden in der uns vorliegenden JAXB- Implementierung noch überschrieben. 111
    • 4 JAXB-API 4.5.3 Zusammenfassung Mit Callback-Mechanismen kann applikationsspezifische Logik in den Marshalling- oder Unmarshalling-Prozess integriert werden. -Klassen erhalten Nachrichten über jedes im Rahmen der Marshallings bzw. Unmarshallings erzeugte Java-Objekt. Über Methoden, die der Signatur der in der -Schnittstelle definierten Metho- den , , ,  entspre- chen, können einzelne Java-Klassen Nachrichten im Rahmen des Marshallings verar- beiten. Beide Mechanismen lassen sich kombinieren. Die Methoden auf Klassenebene werden dann stets vor den allgemeinen Methoden einer -Implementierung aufgeru- fen. Hinweis Generell ist jedoch zu bedenken, dass jeder einzelne Aufruf der Callback-Methoden sich auf die Rechenzeit auswirkt, die für das Marshalling bzw. Unmarshalling benötigt wird. Daher sollten in diesen Methoden keine sehr aufwendigen Verarbeitungen untergebracht werden, vor allem wenn es sich um performancekritische Anwendungen handelt. 4.6 Die Binder-Komponente verwenden Im Übersichtskapitel zur JAXB-Architektur haben wir die -Komponente einge- führt, mit der transparent zwischen zwei Sichten auf ein XML-Dokument hin- und herge- wechselt werden kann. Wir haben also über die Binder-Komponente die Möglichkeit, Änderungen an einer der beiden Sichten vorzunehmen und die andere Sicht durch die Binder-Komponente automa- tisch aktualisieren zu lassen. Dadurch können wir z.B. in einer Anwendung intern mit JAXB arbeiten, obwohl die Daten an anderer Stelle in Form einer DOM-Instanz vorliegen. Die JAXB-Referenzimplementierung unterstützt hierfür derzeit allerdings nur die W3C- DOM-Sicht, die ganz allgemein aus Objekten vom Typ  besteht, die JAXB-Spezifikation erlaubt auch andere DOM-Repräsentationen. Die Komponente trägt also zu Recht den Namen , es werden die jeweils zueinander gehörigen Objekte zweier Sichten aneinandergebunden. Verändern wir nun ein Objekt z.B. in der JAXB-Sicht, kann der Binder den zugehörigen DOM-Knoten der anderen Sicht ein- fach aktualisieren, da er sich die Beziehung zwischen den beiden Objekten merkt. Das funktioniert natürlich auch für den umgekehrten Fall, falls ein DOM-Knoten verändert wird, kann auch das passende JAXB-gebundene Java-Objekt aktualisiert werden. In jedem Fall müssen wir Änderungen aber nur an einem der Objekte vornehmen, der Binder küm- mert sich um den Rest. 112
    • 4.6 Die Binder-Komponente verwenden 4.6.1 Eine DOM-Sicht erstellen Auf den folgenden Seiten werden wir uns häufiger mit der DOM-Sicht auf ein XML- Dokument beschäftigen. Daher sollten wir uns ein kurzes Beispiel anschauen, wie wir eine solche DOM-Sicht auf ein XML-Dokument erzeugen. Der folgende Quelltextauszug er- zeugt eine neue DOM-Sicht durch Parsen eines XML-Dokuments mit der DOM-API der JAXP 1.3.     Wir legen also zunächst eine  an, die uns wiederum einen   bereitstellt. Der  ist in der Lage, XML-Dokumente zu parsen und als Objekte vom Typ  darzustellen. Dieses Objekt stellt das Wurzel- element eines DOM-Baums dar und definiert den Stamm einer Baumstruktur von Knoten des Typs . Damit eventuell vorhandene Namespaces verarbeitet werden, muss das Attribut  der  auf  gesetzt werden. 4.6.2 Die Klasse javax.xml.bind.Binder JAXB vereint die oben beschriebenen Funktionen in einer einzigen abstrakten Klasse, die den Namen Binder trägt. Um einen Überblick über die Funktionsweise des Binders zu be- kommen, sehen wir uns die Methoden dieser Klasse einmal an:                     113
    • 4 JAXB-API          Eine Referenz auf ein Objekt vom Typ  erhalten wir wieder über das  -Objekt, das wir hier mit einer der Klasse  initialisieren:   Der Aufruf von  erzeugt einen Binder speziell für eine W3C-DOM-Sicht. W3C-DOM ist in JAXB die Standardeinstellung. Soll eine andere DOM-API verwendet werden, kann dies durch folgenden Aufruf erreicht werden:   Hier wird der -Methode das Klassenobjekt der -Klasse aus der jeweili- gen DOM-API übergeben. Dadurch erzeugt die JAXB-Implementierung eine - Instanz, die diese DOM-API unterstützt. Hinweis In der uns vorliegenden JAXB-Referenzimplementierung wird derzeit nur die W3C-DOM- API unterstützt. Ein Aufruf von  wird daher generell mit einer   vorzeitig beendet. Hier ist momentan nur der Stan- dardweg über  möglich. Die konkrete Implementierung der abstrakten Methoden aus der -Klasse bleibt hier wieder der JAXB-Implementierung überlassen. Für uns als Anwender ist es völlig transpa- rent, welche konkrete Klasse hier wirklich zurückgegeben wird. Die Methoden der Klasse  können unterteilt werden in Methoden zur Transforma- tion, zur Navigation und zur Synchronisation einer DOM- und einer JAXB-Sicht auf ein XML-Dokument. Die Verwendung dieser Methoden zeigen wir in dem folgenden Ab- schnitt. 4.6.3 Transformation mit unmarshal und marshal Diese Methoden funktionieren ähnlich wie die gleichnamigen Methoden der  - und -Klassen. Die -Methode überführt eine DOM-Sicht eines XML-Dokuments in die entsprechenden Java-Objekte. Wir übergeben dabei das Wurzel- element des DOM-Baums als Parameter. 114
    • 4.6 Die Binder-Komponente verwenden      Dieser Aufruf funktioniert wie dargestellt, wenn die Klasse  an ein gültiges Wurzelelement für ein XML-Dokument gebunden ist und  einem solchen Wurzel- element entspricht. Wie beim gewöhnlichen Unmarshalling kann auch hier explizit als zweiter Parameter noch ein Typ angegeben werden, in den der DOM-Knoten überführt werden soll. Diesen Parameter müssen wir also auf jeden Fall angeben, wenn der aktuelle Knoten kein Wurzelelement darstellt. In diesem Fall besitzt die zugehörige Java-Klasse in der Regel auch keine -Annotation. Der folgende Aufruf liefert daher als Ergebnis ein Objekt vom Typ  zurück.   Die -Methode hingegen überführt einen Java-Objektgraphen in die entsprechende DOM-Sicht. Der erste Parameter der Methode stellt dabei das Wurzelement des zu trans- formierenden Java-Objektgraphen dar. Im Unterschied zur -Methode gibt es hier keinen Rückgabewert. Die Methode verändert direkt den als zweiten Parameter über- gebenen DOM-Knoten.   4.6.4 Navigation mit getXMLNode und getJAXBNode Nachdem wir nun wie oben beschrieben verbundene Objekte der JAXB- und der DOM- Sicht erzeugt haben, können wir mit den Methoden  und  zwi- schen diesen beiden Sichten hin- und herwechseln. Das ist möglich, da der Binder eine Abbildung speichert, in der zu jedem Objekt der zugehörige Partner in der anderen Sicht abgelegt ist. Die Methode  erwartet eine Instanz einer Java-Klasse mit XML- Bindung und liefert den entsprechenden Knoten der DOM-Sicht, falls eine entsprechende Abbildung vorhanden ist. Die Methode  arbeitet umgekehrt, liefert also für einen DOM- Knoten das entsprechende Java-Objekt und erwartet daher einen DOM-Knoten als Parame- ter.     115
    • 4 JAXB-API    4.6.5 Synchronisation mit updateXML und updateJAXB Nachdem wir die Daten einer der beiden Sichten geändert haben, können wir diese Ände- rungen durch Update-Methoden in die jeweils andere Sicht übernehmen. Angenommen, wir haben ein per JAXB gebundenes Java-Objekt in unserer Anwendung geändert und möchten die Änderungen in das DOM-Modell übernehmen. Die JAXB-API gibt uns dafür zwei Methoden an die Hand, deren Aufruf wir hier kurz zeigen:         Die erste Methode überführt das geänderte Java-Objekt in den als zweiten Parameter gege- benen DOM-Knoten. Intern wird dabei ein Marshalling des Java-Objektes in die entspre- chende Stelle im DOM-Modell durchgeführt. Daher wird nicht das gesamte DOM-Modell, sondern nur der übergebene Knoten neu er- zeugt. Dieses Verfahren wird auch „In-Place“-Marshalling genannt. Der zurückgelieferte DOM-Knoten ist im Normalfall identisch zum vorher übergebenen Knoten. Für den Fall, dass sich wesentliche Aspekte des Objekts geändert haben, kann jedoch auch ein neues -Objekt zurückgeliefert werden. Die zweite -Methode ist die bequemere Variante der ersten, die sich den zuge- hörigen DOM-Knoten selbst über die Abbildungstabelle des  holt. Für den umgekehrten Fall, nämlich eine Änderung am DOM-Modell, kann die parallel e- xistierende JAXB-Sicht ebenfalls mit den vorgenommenen Änderungen aktualisiert wer- den. Dazu existiert analog zu  eine Methode , deren Aufruf hier beispielhaft illustriert ist:       116
    • 4.6 Die Binder-Komponente verwenden 4.6.6 Konkrete Anwendungsfälle Bisher haben wir nur kurze Codebeispiele zu den einzelnen Methoden der -Klasse gesehen. Um die Verwendung der -Klasse in einer XML-basierten Anwendung zu verstehen, sehen wir uns im Folgenden zwei konkrete Anwendungsfälle an. Erstellen einer SOAP-Nachricht Im Übersichtskapitel wurde bereits erwähnt, dass die -Klasse häufig zur Erstellung und Verwaltung einer zweiten Sicht auf ein XML-Dokument, z.B. neben einer DOM- Sicht, verwendet wird. Im ersten Anwendungsfall bekommen wir eine solche DOM-Sicht auf ein XML-Dokument als Eingabe. Die eigentliche Datenverarbeitung möchten wir aber mit Java-Klassen durchführen, da der Datenzugriff über die DOM-Knoten doch recht mühsam ist. Daher erstellen wir mit dem Binder eine zweite Sicht auf das XML-Dokument. Erinnern wir uns daher wieder an den Online-Banking-Service. Angenommen dieser Ser- vice wird als Webservice bereitgestellt: Dann muss der Service eventuell auch eine voll- ständige SOAP-Nachricht als Antwort versenden können. Eine SOAP-Nachricht besteht aus einem Umschlag, dem SOAP-Envelope, und der eigent- lichen Nachricht, dem SOAP-Body. Der SOAP-Body enthält die bekannte - Struktur mit den eigentlichen Daten. Als Basis erstellt der Online-Banking-Service die be- schriebene SOAP-Nachricht im DOM-Format mit einem zunächst leeren Response- Element.              Zum Befüllen des -Elements mit den entsprechenden Kunden-, Konto- und Port- folioinformationen kann jetzt die Funktionalität des  eingesetzt werden. Dazu wird zunächst mit Hilfe eines XPath-Ausdrucks das -Element in der DOM-Sicht loka- lisiert und als Knoten  gespeichert. Wie genau die XPath-Syntax aussieht, um ein Element zu lokalisieren, kann in der kurzen XPath-Einführung nachgelesen wer- den. Der Knoten  wird danach mit der -Methode des  in ein Java-Objekt vom Typ  transformiert .Die Anwendung kann dieses Java-Objekt 117
    • 4 JAXB-API jetzt bequem mit Inhalten füllen. Haben wir alle Daten ermittelt, wird die DOM-Sicht auf die SOAP-Nachricht mit den Änderungen der gebundenen Java-Objekte synchronisiert. Die Verbindung zwischen dem Objekt  und dem entsprechenden DOM-Knoten in der Variablen  bleibt durch den  erhalten. Das folgende Beispiel zeigt dies beispielhaft für das Anlegen eines neuen Kunden. Dieser Kunde wird einfach über eine statische Methode erzeugt.                                                      118
    • 4.6 Die Binder-Komponente verwenden                      Nach Ausführen des oben beschriebenen Codes wird als Ergebnis das folgende XML- Dokument erzeugt.                               Die Anwendung muss in diesem Fall nur Schemainformationen über das - Dokument besitzen. Der Rest des Dokuments kann einem beliebigen Schema folgen, das nicht durch Java-Klassen abgebildet sein muss. Das umgebende XML-Dokument kann mit den Mitteln der DOM-API beliebig geändert werden. Die Anwendung muss nur in der La- 119
    • 4 JAXB-API ge sein, das -Element über einen XPath-Ausdruck zu lokalisieren. Die Binder- Komponente eignet sich daher hervorragend für Szenarien, in denen XML-Dokumente nur teilweise verändert werden oder in denen das XML-Dokument für eine Reihe von getrennt programmierten Modifikationen nicht jedes Mal vollständig neu eingelesen werden soll. Schnelle Navigation mit XPath Im zweiten Beispiel wollen wir die DOM-Sicht nutzen, um schnell durch ein XML- Dokument zu navigieren, während die JAXB-Sicht für den Zugriff auf die eigentlichen Daten verwendet wird. Zur schnellen Navigation durch das XML-Dokument nutzen wir dazu die Vorteile von XPath-Ausdrücken in der DOM-Sicht. Gehen wir daher wieder von einem Dokument aus, das ein -Element enthält.                                          Dieses Dokument liegt unserer Anwendung in einem Objekt vom Typ  vor, das wir z.B. durch den Aufruf des Online-Banking-Service erhalten haben (hier durch die fik- tive Methode  dargestellt).  120
    • 4.6 Die Binder-Komponente verwenden Im Portfolio, das durch dieses Dokument beschrieben wird, wollen wir nun den Wert der Wertpapierposition mit dem Namen „BlueSteel Pty. Ltd.“ ändern. Wir könnten dies tun, indem wir durch den Java-Objektgraphen an die entsprechende Stelle der Wertpapierliste navigieren. Im Beispieldokument wäre dies zugegebenermaßen nicht allzu schwer. In komplexeren Dokumentstrukturen, in denen das Element  an verschiedenen Stellen auftreten kann, ist dieses Vorgehen jedoch recht mühsam. Daher nutzen wir XPath-Ausdrücke in der DOM-Sicht, um das gesuchte -Element zu finden. Dazu erstellen wir zunächst ein leeres DOM-Dokument für die DOM-Sicht.    Durch Aufruf der folgenden Methode des  wird dieses Dokument mit den Inhalten aus dem Java-Objekt  befüllt, wobei die Beziehungen zwischen den beiden Sich- ten erhalten bleiben.  Jetzt lassen wir uns per XPath-Abfrage das entsprechende -Element zurücklie- fern. Hier wird eine statische Methode  unserer Utility-Klasse  verwendet. Diese Methode evaluiert einen XPath-Ausdruck und lie- fert das Ergebnis als Knotenobjekt vom Typ  zurück.   Mit Hilfe der Methode  holen wir uns eine Referenz auf ein gebun- denes Java-Objekt vom Typ . An diesem Objekt nehmen wir nun programma- tisch die Änderungen vor. In dem abgedruckten Fall ändern wir nur den Gesamtwert der Position. Danach überneh- men wir die Änderungen in die DOM-Sicht. Das DOM-Dokument wird zuletzt von der Anwendung als XML-Dokument auf die Standardausgabe geschrieben.      Die erzeugte Ausgabe zeigt nun ein XML-Dokument mit der aktualisierten Wertpapierpo- sition.        121
    • 4 JAXB-API                Der Übersichtlichkeit zuliebe ist hier noch einmal das gesamte Listing für das Beispiel auf- geführt:                                           122
    • 4.6 Die Binder-Komponente verwenden                         4.6.7 Zusammenfassung Mit der Binder-Komponente können komfortabel zwei Sichten auf ein XML- Dokument gleichzeitig verwendet werden. Änderungen an einer Sicht werden über einfache Aktualisierungsmethoden mit der je- weils anderen Sicht synchronisiert. Binder hält Informationen über Beziehungen der Elemente zweier Sichten, diese sind auch programmatisch von außen verfügbar. Sinnvoll, wenn wir große XML-Dokumente verarbeiten, von diesen aber nur einen kleinen Teil lesen und verändern wollen. Nur diese Teile werden dann dank des Bin- ders in JAXB-gebundene Java-Klassen umgewandelt. XML-Kommentare bleiben beim Un/Marshalling durch die Binder-Komponente mög- lichst unberührt. Würden wir das komplette XML-Dokument in Java-Objekte und wie- der zurück umwandeln, gingen diese Kommentare verloren. 123
    • 5 XML-Schema zu Java Dieses Kapitel wird sich mit den schemaseitigen Bindungskonfigurationen beschäftigen, die in der JAXB 2.0 spezifiziert sind. Es Kapitel wendet sich an den Leser, dem das Schicksal ein XML-Schema vor die Füße geworfen hat und der nun nach Möglichkeiten sucht, XML-Dokumente dieses Schemas möglichst schnell mit einem schönen Java- Datenmodell zu kapseln. Stück für Stück werden wir in diesem Kapitel darstellen, wie der Schema-Compiler aus einem XML-Schema ein Java-Datenmodell erzeugt – und wie wir über Bindungsdeklarati- onen auch erreichen können, dass das Modell im Detail den vielfältigen Anforderungen genügen kann. Die Beispiele in diesem Kapitel betten wir in den Kontext des Online-Banking-Service ein, dessen Beispielschemas immer wieder Ausgangspunkt für allerlei Konfigurationen sind. Dieses Kapitel bringt die Anforderungen und die als Lösung gebotenen Deklarationen zu- sammen – im Detail werden hier zugunsten der Prägnanz der Beispiele immer wieder Fra- gen offenbleiben. Hier möchten wir auf die JAXB-Referenz dieses Buches verweisen: Dort haben wir jedes Element einzeln in seiner Bedeutung und Anwendung möglichst vollstän- dig beschrieben. 5.1 Bindungskonfigurationen Bindungskonfigurationen bezeichnen die benutzerdefinierte Anpassung der Bindung eines existierenden Schemas an ein Java-Datenmodell. Eine Bindungskonfiguration besteht da- bei aus einer Reihe von Bindungsdeklarationen, in der JAXB-Spezifikation auch Binding Declarations genannt. Der Schema-Compiler einer JAXB-Implementierung verwendet im Normalfall die in der JAXB-Spezifikation definierten Standardeinstellungen, um aus einem bestehenden XML- Schema die entsprechenden Java-Klassen zu generieren. So entstehen z.B. aus einem XML-Namespace auf wohldefinierte Weise Java-Pakete, in denen an diesen Namespace gebundene Java-Klassen zusammengefasst werden. Aus 125
    • 5 XML-Schema zu Java XML-Datentypen entstehen Java-Klassen, auch Value Classes genannt. Die Elemente selbst, also die Instanzen der XML-Datentypen, werden als Instanzen vom Typ   abgebildet. Attribute und Unterelemente werden standardmäßig als Eigenschaften einer Java Bean dargestellt und so weiter. Es gibt aber Anwendungsfälle, in denen reicht uns diese Standardbindung nicht aus. Hier geben wir dann eine Bindungskonfiguration an, welche die generierten Klassen entspre- chend anpasst. Es geht dabei nicht nur um die Anpassung von Standardeinstellungen. Die Bindungskonfiguration kann den generierten Klassen auch zusätzliche Komponenten hin- zufügen, wie etwa durch das Generieren zusätzlicher Methoden. Typische Anwendungsfäl- le, in denen Bindungskonfigurationen genutzt werden, sind z.B.: Dokumentation eines Java-Datenmodells durch Einfügen von Javadoc-Kommentaren. Anpassen der Standardnamensauflösung von XML-Bezeichnern in Java-Bezeichner bei Namenskonflikten im generierten Java-Datenmodell. Konvertierung und Anpassung von Datentypen bei Veränderungen in der Umgebung. Die einzelnen Bindungsdeklarationen, die dazu gemäß JAXB-Spezifikation in einer Bin- dungskonfiguration definiert werden können, werden allerdings nicht als vollständig und ausreichend angesehen. Daher gibt es einen Mechanismus, mit dem jede konkrete JAXB- Implementierung ihre eigenen Bindungsdeklarationen hinzufügen kann. Der Preis für die Benutzung dieser Deklarationen ist jedoch die Portabilität unseres Codes zwischen verschiedenen JAXB-Implementierungen, die wir damit aufgeben. Auf einige Erweiterungen, die bereits die Referenzimplementierung selbst anbietet, wird am Schluss dieses Kapitels eingegangen. Zunächst sollten wir uns allerdings der allgemeinen Definition und Syntax einer Bin- dungskonfiguration widmen. 5.1.1 Eine Bindungskonfiguration definieren Eine Bindungskonfiguration wird bei JAXB, wie könnte es anders sein, in XML verfasst. Dazu werden eine oder mehrere Bindungsdeklarationen angelegt. Ganz allgemein liegen all diese Deklarationen im gleichen Namespace http://java.sun.com/xml/ns/jaxb. Dieser Namespace wird nach allgemeiner Konvention mit dem Präfix  versehen. Das führt dazu, dass wir eine JAXB-Bindungsdeklaration als ein XML-Element mit einem oder mehreren Unterelementen bzw. Attributen definieren. Das äußere Element gibt dabei den Gültigkeitsbereich an, während die eigentlichen Deklarationen durch Attribute oder geschachtelte Elemente angegeben werden.    Diese Bindungsdeklaration veranlasst den Schema-Compiler, alle generierten Klassen se- rialisierbar zu machen, d.h., alle generierten Klassen implementieren das Interface  . Dies kann nützlich sein, wenn die Klassen z.B. als Parameter für 126
    • 5.1 Bindungskonfigurationen RMI-fähige Methoden verwendet werden sollen, oder allgemein überall dort, wo Objektse- rialisierung/-deserialisierung verwendet wird. Der Gültigkeitsbereich wird hier durch das Element  definiert, es handelt sich also um eine globale Einstellung, während die eigentliche Bindungsdeklaration im E- lement  steckt. Zu den einzelnen Gültigkeitsbereichen erfahren wir später noch mehr. Sehen wir uns erst einmal an, wo wir diese Deklaration angeben können. Inline oder extern definieren? Die JAXB-Spezifikation lässt uns bei der Definition einer Bindungskonfiguration die Wahl zwischen zwei Möglichkeiten. Zum einen kann die Konfiguration innerhalb des betreffen- den XML-Schemas definiert werden, dies wird auch eine Inline-Definition genannt. Es ist aber auch möglich, die Bindungskonfiguration in einem separaten XML-Dokument abzu- legen. Eine Bindungsdeklaration selbst, wie oben gesehen, sagt jedoch nichts aus über den Ort, an dem sie definiert wird, bzw. über das Element/Attribut, auf das sie sich auswirkt. Die obige Syntax ist für Inline- und externe Definitionen gleich. Der Wirkungsbereich einer Bin- dungsdeklaration ergibt sich aus dem Kontext, in dem sie definiert wird. Steht die Bin- dungsdeklaration in einer Schema-Annotation zu einem Datentyp, so bezieht sich die Kon- figuration auf diesen Datentyp. Die beiden Vorgehensweisen der Definition haben ihre Stärken und Schwächen. Für eine Definition innerhalb des Schemas, also inline, spricht: Die Zusammengehörigkeit von XML-Schemaelement und Bindungskonfiguration ist auf einen Blick erkennbar. Der Ort des Schemas muss nicht angegeben werden. Beim Verschieben und Verschi- cken des Schemadokuments wird die Bindungskonfiguration stets „mitgenommen“. Es muss im Gegensatz zur externen Definition kein XPath-Ausdruck auf das entspre- chende XML-Schemaelement angegeben werden. Gegen eine Inline-Definition und für eine externe Definition spricht Eine große Anzahl Bindungskonfigurationen innerhalb eines XML-Schemas macht es un- leserlich Eine Bindungskonfiguration in einer externen Datei kann leicht wiederverwendet wer- den, um z.B. die gleiche Konfiguration für mehrere Schemas gleichzeitig anzuwenden. Dadurch wird eine redundante Definition vermieden. Hinweis Natürlich ist es auch möglich, sowohl inline als auch extern definierte Bindungskonfiguratio- nen zu nutzen. Beispielsweise könnte man Bindungsdeklarationen, die allgemeiner Natur sind und für mehrere Schemas gelten können, in einer externen Definition verwalten, während die individuelle Konfiguration durch eine Inline-Konfiguration stattfindet. Zu beachten ist dabei aber, dass pro Schemaelement nur eine Bindungskonfiguration definiert werden kann. Die Konfigurationen müssen daher disjunktiv sein. 127
    • 5 XML-Schema zu Java Inline-Definition – ein Beispiel Ganz allgemein werden Bindungsdeklarationen inline durch ein XML-Element   definiert. Dieses Element gehört zum Grundumfang von XML-Schema. Es dient dazu, ein XML-Schema zu dokumentieren, für Mensch und Maschine zugleich.         Der Schema-Compiler interessiert sich nur für den maschinenlesbaren Teil dieses  -Elements, nämlich den -Teil. Die Bindungsdeklaration befindet sich daher im -Element. Das sehen wir uns einmal an einem konkreten Beispiel an. Das folgende Schemadokument definiert gleich auf oberster Ebene nach dem -Element eine Bindungskonfiguration durch die Angabe der einzelnen Bindungsdeklaration .                       Wie wir hier sehr schön sehen können, besitzt eine Inline-Bindungskonfiguration immer einen Kontext, einen Bezug zu dem Element, in dem sie definiert wurde. In unserem Fall ist dies das -Wurzelelement selbst. Dies ist hier auch notwendig, da wir eine globa- le Bindungsdeklaration mit  angegeben haben. Diese ist daher für das gesamte Schema gültig. 128
    • 5.1 Bindungskonfigurationen Externe Bindungskonfigurationen Sehen wir uns jetzt das Gegenstück zur obigen Inline-Definition an. Die folgende externe Bindungskonfiguration legen wir in einer getrennten Datei binding.xjb ab. Der Name der Datei ist dabei frei wählbar.            Die Datei besitzt als Wurzelelement ein Element , durch das der Schema- Compiler erkennt, dass es sich hier um eine externe Bindungskonfiguration handelt. Das oberste -Element muss die Namespaces http://java.sun.com/xml/ns/jaxb und http://www.w3.org/2001/XMLSchema deklarieren und zusätzlich die JAXB-Version mit dem Element  angeben. Wir sehen hier, dass die Bindungsdeklaration im Element  an sich die gleiche geblieben ist. Da es sich hier aber um eine externe Datei handelt, müssen wir einen Bezug zum Element des XML-Schemas herstellen, das wir konfigurieren möchten. Dies wird im einleitenden Tag  mit dem Attribut  vorbe- reitet, in dem wir in der Bindungskonfiguration das Schema angeben, auf das sich die Kon- figuration bezieht. Eine externe Konfiguration muss hierbei durchaus auch auf mehrere Schemas Bezug nehmen. Mit dieser Angabe weiß der Schema-Compiler jetzt zumindest, welches XML-Schema gemeint ist. Woher soll er aber wissen, welche Knoten wir eigentlich mit dieser Konfigura- tion anpassen wollen? Hier kommt wieder die XPath-API ins Spiel. Ein XPath-Ausdruck eignet sich prima, um das Element unseres XML-Schemas anzugeben, auf das sich die Bindungskonfiguration bezieht. Daher geben wir im verschachtelten - Element mit dem Attribut den Wurzelknoten des XML-Schemas als XPath 1.0-Ausdruck an. Der Schema-Compiler wertet jetzt diesen Ausdruck aus, um das konfigurierte Element zu ermitteln. Über diesen Mechanismus kann jeder beliebige Knoten in einem Schema refe- renziert (und konfiguriert) werden. Hinweis Die externe Definition einer Bindungskonfiguration mag auf den ersten Blick etwas aufwendig erscheinen. In der Praxis hat sie sich jedoch als die übersichtliche Variante bewährt und ist au- ßerdem im Rahmen der Beispielanwendungen zu handhaben – wir werden daher im Folgen- den die einzelnen Bindungskonfigurationen stets als externe Definitionen angeben. 129
    • 5 XML-Schema zu Java 5.1.2 Bindungskonfigurationen per xjc-Task einbinden Wir haben unserer Bindungskonfiguration bereits mitgeteilt, auf welches XML-Schema sie sich auswirken soll. Der Schema-Compiler hat aber noch keinen blassen Schimmer, dass wir diese Bindungskonfiguration beim Generieren der Java-Klassen wirklich anwenden wollen. Wir können dies über eine Erweiterung unseres Build-Skripts tun. Das ANT-Task , das den Schema-Compiler aufruft, wird um das Attribut  erweitert, das eine Referenz auf die Datei  angibt. Es wird dabei angenommen, dass das Schema   und die Bindungskonfiguration  im selben Verzeichnis liegen.                              Prompt beachtet nun der per ANT gestartete Schema-Compiler unsere Konfiguration. 5.1.3 Den XJC-Schema-Compiler programmatisch starten Bisher haben wir stets ein ANT-Skript bemüht, um mit dem Schema-Compiler Java- Klassen zu generieren. Dazu haben wir den -Task aus der JAXB- Referenzimplementierung benutzt. Aber nicht in allen Szenarien steht uns eine ANT- Umgebung zur Verfügung. Es könnten z.B. auch andere Tools wie Maven 1 für den Build- 1 http://maven.apache.org 130
    • 5.1 Bindungskonfigurationen vorgang benutzt werden. Wie auch immer, der ANT-Task selbst ist auch nur eine Art Wrapper um den eigentlichen Schema-Compiler. Der Schema-Compiler kann nämlich problemlos auch „stand-alone“ innerhalb einer Java-Anwendung ausgeführt werden. Wir werden das jetzt einfach machen. Die folgende Beispielklasse erzeugt den gleichen Code wie das obige ANT-Beispiel, allerdings rein programmatisch.                                             Zuerst erzeugen wir in dem Beispiel ein -Objekt mit der Klasse .  131
    • 5 XML-Schema zu Java Danach setzen wir den Paketnamen auf den Paketnamen unserer Beispielklasse. In dieses Paket wird, soweit nicht durch eine Bindungskonfiguration anders definiert, der erzeugte Code generiert. Um eventuelle Fehler bei der Generierung zu behandeln, können wir zusätzlich einen   beim  registrieren. Dazu müssen wir die einfache Schnitt- stelle  implementieren. Unsere Implementierung dieses  sei hier nur kurz dargestellt, da sie für den weiteren Prozess eher zweitrangig ist.                       In unserem Fall gibt dieser  also einfach nur auftretende Fehlermel- dungen auf der Konsole aus. Nachdem wir die Grundvoraussetzungen geschaffen haben, brauchen wir jetzt natürlich noch Input in Form eines XML-Schemas und einer dazugehörigen externen Bindungskon- figuration. Zum Einlesen dieser Dokumente können wir verschiedene Eingabeformate verwenden. In unserem Beispiel wird das Schema über eine  der StAX-API eingelesen. Dieser übergeben wir den Namen der Schemadatei und setzen die System-ID der   auf den URI des Schemas.      Weitere Eingabeformate sind hier noch DOM-Elemente und der  der StAX-API. 132
    • 5.1 Bindungskonfigurationen Der Aufruf für die Bindungskonfiguration ist ähnlich wie der Aufruf zum Einlesen des XML-Schemas, nur wird hier der Bequemlichkeit halber die Methode   genutzt, da unsere Beispielklasse und die Datei  im gleichen Verzeichnis liegen. Als System-ID der  wird hier das Basisverzeichnis gewählt. Dieses Ver- zeichnis nutzt der Schema-Compiler später, um Pfadangaben zu Schemas in der Bindungs- konfiguration aufzulösen.     Mit dem Parsen dieser Dokumente erstellt der  ein Objektmodell mit den vom Schema abgeleiteten Java-Klassen. Dieses Objektmodell binden wir jetzt an ein Ob- jekt vom Typ , das neben dem generierten Code noch zusätzliche Informa- tionen über die Abbildung der Schemakomponenten auf die Java-Objekte enthält.  Momentan sind wir aber nur an dem erzeugten Java-Code interessiert. Diesen können wir über die Methode  erhalten. Als Parameter können wir hier ein Feld von -Erweiterungen (-Plugins) und einen  übergeben. Da wir momen- tan aber keine -Erweiterungen definiert haben, übergeben wir hier einfach .  Als Ausgabe geliefert wird jetzt ein Objekt vom Typ . Dieses Objekt besitzt schließlich eine Methode , mit der die Daten als Java-Klassen in das angege- bene Verzeichnis generiert werden. Die -Methode gibt die Namen der generierten Artefakte auf der Konsole aus.            Damit haben wir den  programmatisch aufgerufen. Das Ergebnis des Aufrufs ist identisch mit dem Ergebnis, das uns zuvor der ANT-Task lieferte. Um in unse- ren Beispielen von ANT-Skripten unabhängig zu sein, werden wir den  auf diese Weise im weiteren Verlauf des Kapitels zur Codegenerierung nutzen. Außerdem erleichtert es die Strukturierung der Beispielaufgaben, da das Anlegen separater Buildskripte entfällt. Grundsätzlich kann aber auch der Aufruf über ein ANT-Skript erfol- gen. 133
    • 5 XML-Schema zu Java Hinweis Die vorgestellte Vorgehensweise zum Einsatz des Schema-Compilers bezieht sich auf die JAXB-Referenzimplementierung. Der dargestellte Quelltext wird nicht ohne weiteres mit an- deren Implementierungen funktionieren. Auf die Beispiele selbst hat das keine Auswirkung. 5.1.4 Externe Bindungskonfigurationen auf der Kommandozeile Wir können dem Schema-Compiler auch externe Bindungskonfigurationen über die Kommandozeile übergeben. Dies ist zwar weniger bequem als der ANT-Task und weniger dynamisch als das programmatische Starten, aber es lässt sich innerhalb von Shell-Skripten dennoch recht gut einsetzen. Daher wollen wir hier auch ein kurzes Beispiel für den Aufruf des Schema-Compilers per Kommandozeile zeigen. Wir übergeben die Dateien mit Bindungskonfigurationen über den Parameter . Es können auch mehrere Konfigurationen verarbeitet werden. Die Reihen- folge der Angabe spielt dabei keine Rolle.  Hier der Befehl mit mehreren Bindungskonfigurationen:   5.1.5 Ein Wort zu Versionen Bisher haben wir ein Attribut unterschlagen, das in den bisherigen Bindungskonfiguratio- nen auftaucht. Das Attribut  wird sowohl bei Inline- als auch bei externen Bin- dungskonfigurationen angegeben, um eine Rückwärtskompatibilität in späteren Versionen der JAXB-Spezifikation gewährleisten zu können. Da wir in diesem Buch ausschließlich mit der Version 2.0 arbeiten, geben wir daher sowohl im -Element bei Inline- Definition als auch im Element bei externer Definition stets die Versi- onsnummer 2.0 an. 5.1.6 Der Sichtbarkeitsbereich Bindungskonfigurationen besitzen immer einen Sichtbarkeitsbereich, auch Scope genannt. Der Begriff „Scope“ lässt sich leider nur schwer ins Deutsche übertragen, „Sichtbarkeits- bereich“ oder „Wirkungsbereich“ können hier nur als gute Näherung angesehen werden. Mit dem Scope einer Bindungskonfiguration ist also die Menge der Schemaelemente ge- meint, auf die sich die Bindungskonfiguration bezieht. In JAXB gibt es vier verschiedene Sichtbarkeitsbereiche bzw. Scopes. Global: Eine globale Einstellung gilt für sämtliche Schemas, die mit dieser Bindungs- konfiguration verarbeitet werden. Das bedeutet auch, mit den Schemaelementen  134
    • 5.1 Bindungskonfigurationen  und  referenzierte Schemas werden rekursiv einbezogen, d.h., für alle die- se Schemas gilt die Einstellung ebenfalls. Schema: Eine schemalokale Einstellungen ist an ein bestimmtes Schema gebunden. Wenn mit dieser Bindungskonfiguration mehrere Schemas verarbeitet werden, dann können für jedes einzelne Schema andere Einstellungen definiert werden. Typ/Element: Gültig für einzelne, global definierte Typen und Elemente einer Schema- instanz. Komponente: Gültig für Unterelemente einer Typ- bzw. Elementdeklaration einer Schemainstanz. Diese Sichtbarkeitsbereiche werden durch die folgende Auswahl an Elementen repräsen- tiert, die jeweils eine Reihe von Bindungsdeklarationen zu einer Ebene gruppieren. Einige Bindungsdeklarationen sind in mehreren dieser Ebenen zu finden und können sich überla- gern, wie wir am Ende des Kapitels noch näher betrachten werden. <property> Komponente Typ / Element <class> Schema <schemaBindings> Global <globalBindings> Abbildung 5.1 Sichtbarkeitsbereiche der Bindungsdeklarationen 5.1.7 Zusammenfassung Das Standardverhalten des Schema-Compilers kann durch Bindungskonfigurationen angepasst werden. Eine Bindungskonfiguration besteht aus einer Reihe von Bindungsdeklarationen. Bindungskonfigurationen können sowohl inline im XML-Schema als auch über externe Konfigurationsdateien definiert werden. Bindungskonfigurationen können auf der Kommandozeile, im -Task oder auch pro- grammatisch an den Schema-Compiler übergeben werden. 135
    • 5 XML-Schema zu Java Die Bindungsdeklarationen gliedern sich in verschiedene Sichtbarkeitsbereiche. Je nach Sichtbarkeitsbereich ist eine Bindungsdeklaration für alle Schemas, das aktuelle Schema oder auch nur einzelne Elemente oder Datentypen eines Schemas gültig. 5.2 Die erste Bindungskonfiguration Genug der Theorie – auf zu den Bindungskonfigurationen! Sehen wir uns jetzt ein Beispiel an. Wir befinden uns wieder bei unserem Banking-Service. Wir möchten sichergehen, dass die Daten, die der Service versendet, auch vollständig sind. Dazu fragen wir ab, ob die Ei- genschaften der einzelnen Objekte, z.B. des -Objektes, auch befüllt sind. Eine Lösung wäre, mit der Zugriffsmethode der jeweiligen Java Bean-Eigenschaft den Wert zu holen und auf  abzuprüfen. Dies muss natürlich für jede Eigenschaft gesche- hen. Der erstellte Code könnte für ein Account-Objekt  etwa so aussehen:      Um dieses Vorgehen zu generalisieren, können wir uns vom Schema-Compiler zu jeder Eigenschaft aber auch eine -Methode generieren lassen. Diese liefert , wenn das Objekt gesetzt ist, und  falls es nicht gesetzt ist. Mit solchen Methoden könnten wir eine Überprüfungsroutine schreiben, die automatisch diese Methoden aufruft, um die Elemente zu überprüfen. Als Beispiel seien hier nur die Möglichkeiten der aspektorientierten Programmierung genannt, die automatisch Methoden aufrufen, die einem bestimmten Muster entsprechen. Wir teilen dem Schema-Compiler also über die Bindungsdeklaration   mit, dass er solche -Methoden generieren soll. Die externe Bin- dungsdefinition lautet wie folgt.         Wir haben hier also wieder eine globale Bindungsdeklaration mit dem Tag  angegeben. Das bedeutet, dass alle Java-Klassen unseres kleinen Datenmodells jetzt mit -Methoden bestückt werden. Die Generierung der Java- Klassen starten wir wieder wie folgt mit dem gleichen Java-Aufruf (hier nur der Vollstän- digkeit halber noch einmal als -Methode). 136
    • 5.2 Die erste Bindungskonfiguration                                 Betrachten wir die generierte -Klasse. Hier sehen wir das Resultat der Bindungs- konfiguration. Jede Java Bean-Eigenschaft besitzt jetzt zusätzlich eine -Methode, die überprüft, ob die Eigenschaft gesetzt ist.                      137
    • 5 XML-Schema zu Java           Das ist zwar nicht Java Bean-konform, aber auch nicht ganz unpraktisch. 5.2.1 Zusammenfassung Durch Bindungsdeklarationen können Klassen angepasst, aber auch durch zusätzliche Methoden erweitert werden. Eine globale Bindungsdeklaration wirkt sich auf alle Elemente eines Schemas aus. Im- portierte Schemas werden ebenfalls einbezogen. 5.3 Fünf Bindungsdeklarationen für den Alltag Im folgenden Abschnitt werden wir die fünf Tibeter in der Domäne der Bindungsdeklara- tionen kennen lernen. Mit diesen können wir alle wesentlichen Anpassungen unseres gene- rierten Datenmodells vornehmen. Es handelt sich hierbei um Bindungsdeklarationen ver- schiedener Sichtbarkeitsbereiche. Wir werden dazu eine Bindungskonfiguration Schritt für Schritt mit den Bindungsdeklarationen erweitern. Ausgangspunkt ist hier das - Schema mit den drei importierten Schemas ,  und . Die fünf wesentlichen Bindungsdeklarationen lauten:      5.3.1 Aufzählungen anpassen mit jaxb:collectionType In jeder Anwendung wird mit Aufzählungen wie Listen und Mengen gearbeitet. In Java handelt es sich in der Regel um Instanzen der Schnittstellen ,  und  oder um ein Java-Array. In einem XML-Schema sind Listen weniger augenfällig, aber ebenso oft durch das folgen- de Konstrukt definiert, das hier am Element  aus den Beispielschemas dargestellt ist: 138
    • 5.3 Fünf Bindungsdeklarationen für den Alltag    Aus einem solchen Element generiert der Schema-Compiler standardmäßig die folgende Java-Eigenschaft vom Typ :                Hier wird also nur die Schnittstelle  als Typ angegeben. Es bleibt dem Schema- Compiler überlassen, welche -Implementierung in der Anwendung verwendet wird. Die Implementierung der Zugriffsmethoden für die Eigenschaft  offenbart, dass der Schema-Compiler hier eine Liste vom Typ  erzeugt. Generell möchten wir viel- leicht in der Anwendung einen anderen Listentyp verwenden, beispielweise den Typ  , da dieser Listentyp einen synchronisierten, thread-sicheren Zugriff auf seine Elemen- te bietet. Dieses können wir mit Attribut  der Bindungsdeklaration   erreichen, der wir als Parameter eine Implementierung von  angeben können.           Diese Bindungskonfiguration bezieht sich auf das -Schema, das wir im einlei- tenden Element mit dem Attribut  angegeben haben. Da wir den Listen- typ für die gesamte Anwendung konfigurieren möchten, wählen wir über das Attribut  über den XPath-Ausdruck den Schemaknoten als Ziel. Damit sind alle hier angegebenen Bindungsdeklarationen für das Schema  und alle importierten Schemas also ,  und  gültig. Die Bindungs- deklaration  gibt den verwendeten Listentyp an. Nach dem Ausführen des Schema-Compilers sieht die Klasse  so aus. 139
    • 5 XML-Schema zu Java       Hier wird also gleich bei der Definition der Variablen  der korrekte Listentyp  zugewiesen. Damit ist ein synchronisierter Zugriff auf unsere Optionselemente gewährleis- tet. 5.3.2 Paketnamen anpassen mit jaxb:package In all unseren XML-Schemas haben wir bisher Namespaces mit URLs der Form http://jaxb.transparent/<Schema-Name> deklariert. Wenn nicht anders angegeben, gene- riert der Schema-Compiler aus diesen Namespaces die entsprechenden Paketnamen, in de- nen er die Java-Klassen ablegt. Für den Namespace http://jaxb.transparent/customer bedeutet dies z.B., dass die generier- ten Klassen im Paket  abgelegt werden. Wenn wir in den bisherigen Beispielen nachschauen, befinden sich die Klassen jedoch immer in Paketen wie . Wie kommt dies zustande? Beim Aufruf des Schema-Compilers können wir mit  einen Standardpaketnamen angeben:   Dieser überschreibt dann das Standardverhalten. Doch für unsere Anwendung ist dies viel- leicht nicht optimal. Wir wollen die einzelnen Schemas vielleicht in getrennten Paketen ablegen, und wir möchten einen anderen Paketnamen wählen als den, der sich durch den Namespace ergibt. Angenommen wir wollen die aus den Beispielschemas generierten Klassen in der folgen- den Paketstruktur organisieren:          140
    • 5.3 Fünf Bindungsdeklarationen für den Alltag Die abgedruckte Paketstruktur soll durch ein führendes Paket  und ein Paket  (für Domain Object Model) komplettiert werden. Mit der Bindungsdeklaration  und dessen Attribut kann ein benutzer- definierter Paketname für ein XML-Schemadokument gesetzt werden. Da diese Bindungs- deklaration für das gesamte Schema gültig ist, wird sie innerhalb des -Elements deklariert. Für das -Schema sieht die Bin- dungskonfiguration so aus:              Das Element  definieren wir auf gleicher Ebene wie zuvor die globale Bindungsdeklaration . Sie hängt sozusagen am Schemaknoten des  -Schemas. Wir hätten diese Konfiguration auch inline im Schemadokument definie- ren können, die externe Konfiguration würde dabei weiterhin gelten. Wir nutzen in diesem Fall aber nur die externen Bindungskonfigurationen. Die obige Konfiguration setzt jedoch nur den neuen Paketnamen für das - Schema. Wir müssen jetzt noch analog die Paketnamen für die anderen Schemas deklarie- ren. Da das -Schema diese Schemas importiert, sind sie dem Schema-Compiler be- kannt, und wir können einfach mit dem -Attribut auf das jeweilige Schema verweisen. Das Ergebnis ist dann die folgende, etwas umfangreichere Konfigura- tion.                   141
    • 5 XML-Schema zu Java                 Diese Bindungskonfiguration übergeben wir jetzt wieder an den Schema-Compiler. Nach Ausführen des Schema-Compilers werden wir feststellen, dass die Klassen jetzt fein säu- berlich in die folgenden vier Pakete abgelegt werden.     Die Klassen selbst ändern sich nicht. Das wird sich im nächsten Abschnitt allerdings schwer ändern. Hinweis Die Bindungsdeklaration  in Konstellation mit dem Attribut  über- schreibt alle anderen Einstellungen für Paketnamen, die an den Schema-Compiler übergeben wurden. 5.3.3 Generierte Klassen anpassen mit jaxb:class Wie schon die Paketnamen zuvor, können wir auch die generierten Klassen anpassen. Da- für gibt es die Bindungsdeklaration . Bisher haben wir nur Bindungsdeklarati- onen auf globaler und auf Schemaebene gezeigt. Dies ist die erste Bindungsdeklaration auf der Typ- bzw. Elementebene, die wir darstellen. Da JAXB aus den global definierten XML-Datentypen und Elementen jeweils eine Java- Klasse oder Value Class generiert, definieren wir die -Deklaration im Kontext eines solchen Datentyps oder Elements. Ein häufiger Anwendungsfall ist das Umbenennen der generierten Klassen. Mit der bishe- rigen Standardbindung erhalten wir für das Element  eine entsprechende Java- Klasse mit dem Namen .    142
    • 5.3 Fünf Bindungsdeklarationen für den Alltag                 Diese Klasse wollen wir jetzt in  umbenennen, da wir über den Namen vielleicht deutlich machen wollen, dass das -Element später im Banking-Service den Körper einer SOAP-Nachricht darstellt. Einen alternativen Namen können wir mit dem Attribut  der Bindungsdeklaration angeben.  Versehen wir also das XML-Element  mit der Bindungsdeklaration  und übergeben dem Attribut  den Wert :                              143
    • 5 XML-Schema zu Java         Wir haben der Bindungskonfiguration also ein zusätzliches -Element hin- zugefügt. Dies ist notwendig, da wir die Deklaration  nur auf das Element  anwenden wollen. Der XPath-Ausdruck  liefert uns genau dieses Ele- ment zurück. Darin verschachteln wir die beschriebene Deklaration und erhalten durch den Schema-Compiler die folgende Klasse.                           Wie wir sehen, hat sich nur der Name der Klasse geändert, die Annotation  zeigt weiterhin auf das XML-Element . Alternative Implementierungen mit jaxb:class Die -Bindungsdeklaration kann allerdings noch mehr. Sie besitzt ein zweites Attribut , mit dem wir eine alternative Implementierungsklasse für dieses Element an- geben können. Das bedeutet allerdings nur, dass die -Klasse einen anderen Rückgabewert für die -Methode bekommt. 144
    • 5.3 Fünf Bindungsdeklarationen für den Alltag Schauen wir uns ein Beispiel für die Klasse  an. Eine alternative Imp- lementierung dieser Klasse soll durch die fiktive Klasse  gegeben sein.                   Starten wir den Schema-Compiler mit dieser Bindungskonfiguration, wird die Klasse   entsprechend abgeändert. Die Methode  weist jetzt als neuen Rückgabetyp  auf.             Diese Bindungsdeklaration macht vor allem dann Sinn, wenn der Schema-Compiler durch die globale Bindungsdeklaration  angewiesen wurde, nur Java- Schnittstellen statt konkreter Implementierungsklassen zu generieren. In diesem Fall kön- nen wir mittels des -Attributs eigene Implementierungsklassen angeben, die z.B. mit einem anderen Tool generiert wurden. 5.3.4 Änderungen auf Komponentenebene mit jaxb:property Nachdem wir Bindungsdeklarationen auf globaler Ebene, auf Schemaebene und auf der Typ-/Elementebene gesehen haben, wenden wir uns jetzt der Komponentenebene zu. Das bedeutet, wir werden Anpassungen an Elementen oder Typen machen, die nicht auf globa- 145
    • 5 XML-Schema zu Java ler Ebene definiert sind, aus denen folglich auch keine eigenen Java-Klassen generiert werden. Solche Komponenten werden vom Schema-Compiler üblicherweise an eine Java Bean- Eigenschaft gebunden. Mit der Bindungsdeklaration  können wir benut- zerdefinierte Anpassungen für diese Eigenschaften vornehmen. Einige dieser Anpassungen können auch auf anderen Ebenen definiert werden und wurden bereits behandelt wie etwa  oder . Wir werden uns daher besonders auf die speziell für Eigenschaften vorgesehenen Bin- dungsdeklarationen konzentrieren. Wie Bindungsdeklarationen auf mehreren Ebenen defi- niert werden, wird der vorletzte Abschnitt behandeln. Namen einer Eigenschaft anpassen Doch zunächst einmal etwas Einfaches. Wie schon bei Paketen und Klassen kann auch für einzelne Eigenschaften der generierte Name vorgegeben werden. Mit dem Attribut  der Bindungsdeklaration  wird der Name angegeben, den die aktuell selek- tierte Komponente, sprich ein ,  oder auch ein , im Java- Code tragen soll. Schauen wir uns dazu einmal das -Schema an. Der Datentyp  besitzt zwei Unterelemente  und .            Aus diesen Namen kann nun wirklich nicht abgeleitet werden, dass es sich hier jeweils um Listen von Wertpapieren bzw. Optionen handelt. Daher erweitern wir die bisherige Bin- dungskonfiguration um eine kleine Namensanpassung mit der - Bindungsdeklaration.              146
    • 5.3 Fünf Bindungsdeklarationen für den Alltag         Die beiden Elemente bekommen jeweils das Suffix „List“, um sie als Aufzählungen zu kennzeichnen. An diesem Beispiel kann man außerdem sehr gut die Schachtelung von - Elementen erkennen. Durch das Verschachteln eines Elements kann ein XPath-Ausdruck jeweils auf dem vorhergehenden Ausdruck aufbauen. Die Klasse  besitzt nach erneuter Generierung die folgenden Eigenschaften.                        Elementinformationen mit generateElementProperty In der Standardeinstellung des Schema-Compilers werden die zu einem Schemaelement generierten Java Bean-Eigenschaften mit entsprechenden Java-Datentypen versehen. Das hat den Vorteil, dass das entstehende Java-Datenmodell „natürlich“ ist, also keinen Hin- weis darauf gibt, dass es auf einem XML-Datenmodell basiert und durch eine JAXB- Implementierung generiert wurde. Es bedeutet aber auch, dass bestimmte XML-spezifische Informationen nicht abgebildet werden. JAXB hält für jedes XML-Element Informationen über den Inhalt, den Sichtbar- keitsbereich und den Typ vor. Benötigen wir diese Informationen in unserer Anwendung, können wir den Schema-Compiler mit der Bindungsdeklaration   anweisen, uns statt des Java-Datentyps eine Eigenschaft vom Typ  zu generieren. 147
    • 5 XML-Schema zu Java Die Klasse  bietet zusätzliche Informationen über die folgenden Methoden: : Gibt an, ob das XML-Element leer ist. : Gibt an, ob das XML-Element global deklariert ist. : Gibt true zurück, wenn der Typ des XML-Elements im Instanz- dokument vom deklarierten Typ im Schema abweicht, z.B. bei Angabe von . : Liefert den Namen des XML-Elements zurück. Dieser muss nicht zwingend dem deklarierten Namen aus dem Schema entsprechen. : Gibt den Sichtbarkeitsbereich des XML-Elements zurück. Gibt   zurück, falls das Element global ist, andernfalls wird der Datentyp des überge- ordneten Elements aus dem XML-Schema zurückgegeben, in dem das Element ver- schachtelt ist. : Gibt den Java-Typ zurück, auf den dieses XML-Element abgebil- det wird. Eine Anforderung in unserer Beispielanwendung könnte sein, dass wir überprüfen müssen, ob die Kunden- und Kontodaten in einem -Element gesetzt sind. Dieses  -Element wird vom Banking-Service als XML-Dokument geliefert. Wenn die Eigenschaften  und  als -Instanzen vorliegen, können wir einfach mit  abfragen, ob diese Elemente vorhanden sind oder nicht. Den -Teil unserer bisherigen Bindungskonfiguration erweitern wir also folgenderma- ßen, um den Eigenschaften  und  den Typ  zuzuweisen.                          Die erzeugte Klasse  hat jetzt die folgenden Eigenschaften: 148
    • 5.3 Fünf Bindungsdeklarationen für den Alltag                            Wenn wir mit dem soeben erzeugten Java-Datenmodell ein XML-Dokument, das wir vom Banking-Service bekommen haben, transformieren, bekommen wir die Kunden und Kon- todaten als -Objekte. Das folgende Listing illustriert dies.         attachmentRef Es definiert, ob XML-Attachments als  aufgelöst wer- den sollen ( ) oder ob in einer entsprechenden Eigenschaft nur ein Verweis auf das XML-Attachment gespeichert wird ().    Diese Einstellung ist relevant für Umgebungen, die eine optimierte Speicherung eines XML-Dokuments unterstützt; beispielsweise in Webservice-Umgebungen oder innerhalb der Kommunikationsschicht eines Enterprise Service Bus. Allein das Aufsetzen einer sol- 149
    • 5 XML-Schema zu Java chen Umgebung würde ein halbes Buch füllen, weswegen wir in hier nur am Rande auf diesen Aspekt der JAXB eingehen. Konstanten erzeugen mit fixedAttributeAsConstantProperty In der Regel werden Attribute, die im XML-Schema mit  deklariert wurden, als normale Eigenschaften der resultierenden Java Bean generiert. Einziger Unterschied zu einer gewöhnlichen Eigenschaft: Sie ist standardmäßig auf den als  angegebenen Wert gesetzt. Alternativ kann über die Einstellung  ein solches Attribut als Konstante der resultierenden Java Bean generiert werden. Als Beispiel fügen wir unserem -Schema ein neues Attribut  hinzu, das die Währung dieses Kontos darstellt. Der Datentyp  hat also folgende Struktur.           Generieren wir die Klasse  nun wie bisher mit dem Schema-Compiler, wird eine ganz gewöhnliche Java Bean-Eigenschaft  vom Typ  erzeugt. Allerdings gibt der Getter für die Eigenschaft  den mit  definierten Wert  für Euro zurück, falls kein Wert für  gesetzt wurde. Das Attribut  gibt hier also einen Standardwert an. Dies kann nützlich sein, wenn wir die Währung variabel halten, jedoch auf die Standardwährung Euro zurückgreifen wollen, wenn das Attribut im XML-Dokument nicht gesetzt wurde.                    150
    • 5.3 Fünf Bindungsdeklarationen für den Alltag         Soll die Währung jedoch fest im XML-Schema verdrahtet werden, darf der Wert für   nicht geändert werden. Dies ist äquivalent zu einer Java-Konstanten, die wir norma- lerweise mit  definieren würden. Um aus dem Attribut  eine solche Konstante zu generieren, erweitern wir die Bindungskonfiguration mit der Deklaration  und setzen ihren Wert auf .                  Die Eigenschaft  der Klasse  ist jetzt als fixe Währung mit dem Wert EUR vorbelegt und kann nicht mehr verändert werden.                  151
    • 5 XML-Schema zu Java     Wir sehen hier zusätzlich noch ein leeres Kommentarfeld oberhalb der Eigenschaft  . Auch diese Kommentare können wir durch eine Bindungskonfiguration befüllen, wie der nächste Abschnitt zeigen wird. 5.3.5 Dokumentieren mit jaxb:javadoc Das Generieren von Klassen durch den Schema-Compiler ist recht praktisch und spart eine Menge Aufwand. Eines wird dabei jedoch häufig vergessen: die Dokumentation. Das ist sicher kein neues Problem in der Informatik, jedoch stellt es sich bei generierten Klassen als besonders problematisch heraus. Dokumentieren wir die Klassen von Hand, so geht die Dokumentation bei einer Neugene- rierung der Klassen möglicherweise verloren. Die Dokumentation sollte deswegen an der Quelle der Klassen, dem XML-Schema geschehen. Das erreichen wir über die Bindungs- deklaration . Die Bindungsdeklaration  ist sehr flexibel. Genau wie echte Javadoc-Kommentare im Quellcode lässt sie sich an den verschiedensten Elementen definieren. Es können  -Bindungsdeklarationen für Pakete, Klassen, Methoden und viele andere Elemente de- finiert werden. Wir geben hier für die Beispielanwendung  Kommentare auf Paketebene, auf Klassenebene und Komponentenebene an. Da die Bindungskonfiguration jetzt komplett ist, führen wir sie hier noch einmal in voller Länge an.                         152
    • 5.3 Fünf Bindungsdeklarationen für den Alltag                                    Diese Bindungskonfiguration zeigt, wie die Kommentare an den entsprechenden Stellen gesetzt werden müssen. In Javadoc sind häufig HTML-Tags zur Formatierung vorhanden. Diese können jedoch nicht ohne weiteres übernommen werden. Wer sich fragt, ob den Autoren bei der ersten Definition ein Tippfehler unterlaufen ist, kann beruhigt sein. Die HTML-Tags müssen ent- sprechend konvertiert werden, um nicht als XML-Elemente der Bindungskonfiguration erkannt zu werden. Daher wird die öffnende Klammer durch die Zeichenfolge  ersetzt. Diese Konvertie- rung können wir uns auch sparen, indem der gesamte Kommentar in ein -Element verpackt wird, das dem XML-Parser mitteilt, dass die folgende Zeichenkette nicht geparst werden soll.   Das Ergebnis dieser Deklarationen ist eine zusätzliche Datei package.html, die den Kom- mentar für die Paketebene enthält sowie Kommentarfelder in den Klassen  und . 153
    • 5 XML-Schema zu Java Listing 5.1 Inhalt der Datei package.html   Listing 5.2 Die Klasse SoapResponseBody                     Listing 5.3 Die Klasse Account                          154
    • 5.4 XML-Bezeichner anpassen 5.3.6 Zusammenfassung Der verwendete Collection-Datentyp lässt sich durch die globale Deklaration  anpassen. Auf Schemaebene können wir mit  den Paketnamen der generierten Klassen anpassen. Einstellungen auf Klassenebene werden durch die Deklaration  vorge- nommen. Die Deklaration  bietet eine Reihe von Konfigurationsmöglichkeiten auf Komponentenebene. Teilweise überlagern sich diese Einstellungen mit globalen Deklarationen. Javadoc-Kommentare können in der Bindungskonfiguration auf Schema-, Klassen- und Komponentenebene durch  angegeben werden. 5.4 XML-Bezeichner anpassen Außer dem -Attribut einiger Bindungsdeklarationen wie ,  oder   haben wir uns um die Benennung unserer XML-Elemente noch keine allzu großen Gedanken gemacht. Aus der Sicht von XML brauchen wir das eigentlich auch nicht. Die XML-Spezifikation gibt uns relativ viel Freiraum, was die Benennung von Elementen, Att- ributen und Datentypen angeht. Der lexikalische Raum für gültige Bezeichner wird durch den Typ  festgelegt.  wird von der XML-Spezifikation als non colonized name definiert. Ein solcher Bezeichner beginnt mit einem Buchstaben und enthält keinen Doppelpunkt, ansonsten sind aber viele Sonderzeichen erlaubt. Außerdem trennt XML die Namensräume für die Be- zeichnung von Elementen, Attributen, Datentypen und Gruppen. So kann ein Datentyp den gleichen Bezeichner verwenden wie ein Element. Auf der Java-Seite sieht es anders aus, denn Java stellt etwas strengere Anforderungen an die Benennung von Bezeichnern. Es gibt Schlüsselwörter und Sonderzeichen, die in Java bereits mit Semantik behaftet sind und daher nicht verwendet werden können, wie z.B. die Datentyp-Bezeichner , ,  etc. Andere Zeichen wie der Bindestrich sind als Operatoren vergeben. Diese Einschränkungen müssen wir bei einer Bindung eines XML-Datenmodells an ein Java-Datenmodell unbe- dingt beachten. Andere Einschränkungen sind nicht zwingend vorgeschrieben, werden a- ber in der Java-Programmierung allgemein befolgt. Diese ungeschriebenen Java-Namenskonventionen wollen wir natürlich nach Möglichkeit auch befolgen, wenn wir Java-Klassen aus unserem XML-Schema erzeugen. Um diese zwei Welten zu vereinen, löst der Schema-Compiler die XML-Bezeichner nach einem Standardalgorithmus in Java-Bezeichner auf. 155
    • 5 XML-Schema zu Java Mit Bindungsdeklarationen können wir von diesem Standardverhalten abweichen, falls un- sere Anwendung dies erfordert. Im Folgenden werden wir daher einige Bindungsdeklarationen kennenlernen, die uns hel- fen, Namenskonflikte in unseren XML-Schemas aufzulösen und Java-konforme Bezeich- ner zu erzeugen. Um einige Namenskonflikte zu provozieren, werden wir unsere Beispielschemas modifi- zieren. Die dabei entstehenden Konflikte lösen wir mit den entsprechenden Bindungsde- klarationen auf. 5.4.1 Einzelne Namenskonflikte auflösen Zunächst nehmen wir einmal das folgende -Schema als Ausgangsbasis.                                    Die Änderung am Schema ist hier fett unterlegt. Das globale Kontoelement heißt jetzt wie der komplexe Typ auch . Starten wir den Schema-Compiler jetzt mit folgender Bindungskonfiguration:       156
    • 5.4 XML-Bezeichner anpassen    Diese Bindungskonfiguration veranlasst den Schema-Compiler, für alle globalen Elemen- ten eine eigene Klasse zu generieren. Beim Ausführen des Schema-Compilers erhalten wir jetzt den folgenden Fehler:   Da der komplexe Typ  und das globale Element  sich namensmäßig ü- berschneiden, kommt es hier auch zu einem Namenskonflikt, denn der Schema-Compiler erzeugt für beide Elemente eine Klasse mit dem Namen . Dieses Problem können wir aber recht schnell mit der Bindungsdeklaration  lösen, mit der wir den Namen einer generierten Klasse individuell anpassen können. Die folgende Bindungsdeklaration löst das obige Problem.             Das globale Element  wird mit dieser Konfiguration als Klasse  abgebildet, während der komplexe Typ die Klasse  bekommt. Auf diese Weise können wir mit recht einfachen Mitteln einen Namenskonflikt auflösen. 5.4.2 Präfixe und Suffixe mit jaxb:nameXmlTransform Treten Namenskonflikte schemabedingt häufiger auf, kann es recht mühsam werden, wie vorher gezeigt, die Konflikte einzeln mit Bindungsdeklarationen auf Klassenebene aufzu- lösen. Vor allem in größeren Datenmodellen kommt es häufiger vor, dass sich Elemente, Daten- typen oder Gruppen überschneiden. In solchen Fällen ist es günstiger, eine allgemeine Namensstrategie festzulegen. Eine solche können wir mit Hilfe der Bindungsdeklaration  definieren. Mit dieser Deklaration können wir Elementen, Datentypen und Gruppen automatisch Prä- fixe und Suffixe zuordnen, ohne die Namen von Hand anpassen zu müssen. XML lässt ja, wie an anderer Stelle bereits erwähnt, gleiche Namen innerhalb dieser vier Gruppen zu, da deren Namensräume voneinander getrennt sind. Die Bindungsdeklaration wird auf Schemaebene definiert, gilt also für die Bezeichner ei- nes einzelnen Schemas, importierte Schemas zählen nicht zum Sichtbarkeitsbereich. Eine 157
    • 5 XML-Schema zu Java alternative Bindungskonfiguration für unseren Namenskonflikt von vorhin könnte mit der Deklaration  so gelöst werden.                  Mit dem ersten Unterelement  wird allen global definierten Datentypen das Suf- fix  hinzugefügt. Für Elemente hingegen wird ein Suffix  vergeben. Evtl. hinzukommende Gruppen werden im Java-Modell mit einem Präfix  versehen, während anonyme Datentypen, also Datentypen ohne -Attribut, sowohl ein Präfix als auch ein Suffix erhalten. Wenn wir diese Bindungskonfiguration an den Schema-Compiler übergeben, sind wir zu- nächst einmal erstaunt. Wir bekommen eine Fehlermeldung!    Wie kann das sein? Nun, aus dem komplexen Typ  wird mit der Bindungskonfi- guration die Klasse . Diese überschneidet sich jetzt aber leider mit der Auf- zählung . Um das zu vermeiden, ändern wir den Namen der Aufzählung wie folgt:        Die Aufzählung  haben wir also zu  geändert. Das löst unter Umständen das aktuelle Problem, zeigt aber überdeutlich, dass Namenskonflikte in der XML-Java-Datenbindung immer wieder auftreten können und manuell behoben werden müssen. 158
    • 5.4 XML-Bezeichner anpassen 5.4.3 Unterstriche verarbeiten mit jaxb:underScoreBinding Wenn wir nach der Umbenennung der -Deklaration von  zu   den Schema-Compiler erneut ausführen, erhalten wir immer noch die gleiche Fehlermeldung. Der Grund ist, dass der Schema-Compiler standardmäßig einen Unterstrich als Trennzei- chen zwischen zwei Wörtern interpretiert. Häufig wird der Unterstrich in XML genau zu diesem Zweck verwendet. In der Java-Welt hat es sich allerdings etabliert, den sogenann- ten Camel-Case zu verwenden. Dabei werden aufeinanderfolgende Wörter durch Großbuchstaben getrennt. Genauso ver- hält es sich mit dem Namen , dieser Name wird von der JAXB- Implementierung zu  zusammengefasst und als Name der entsprechenden Enumeration in Java genommen. Dadurch ergibt sich dann auch der Namenskonflikt mit dem komplexen Typ  , den wir durch die letzte Bindungskonfiguration erzeugt haben. Aber auch für dieses Problem gibt es Abhilfe. Das Standardverhalten, nämlich das Ersetzen der Unterstriche durch Großbuchstaben, lässt sich beeinflussen durch die Bindungsdeklaration . Die bereits bekannte Standardeinstellung ist hier . Um die Unterstriche zu über- nehmen, verwenden wir jetzt den Wert  in der global definierten Bindungs- deklaration.                    Jetzt gibt es keine Namenskonflikte mehr, denn der Unterstrich im Typ  bleibt nun auch in Java erhalten. Damit sieht die generierte Klasse  unseres Schemas wie folgt aus.        159
    • 5 XML-Schema zu Java           Das Verhalten für Unterstriche ist nur eins der Standardverhalten, das die JAXB beim Auf- lösen von XML-Bezeichnern spezifiziert. Im nächsten Teil sehen wir noch weitere Stan- dardauflösungen im Zusammenhang mit Aufzählungen bzw. Enumerationen. 5.4.4 Bezeichner in Enumerationen Der einfache Datentyp  ist als XML-Enumeration definiert und wird in die folgende Java-Enumeration umgewandelt:              Eine Enumeration stellt in Sachen Bezeichner einen Extremfall dar. XML ist hier sehr großzügig, was die erlaubten Bezeichner für die Werte in einer Enumeration betrifft. Das Attribut eines -Elements besitzt den Datentyp , kann also beliebige nicht komplexe Datentypen aufnehmen. Java stellt hier aber für Werte einer Enumeration die gleichen Anforderungen wie für ande- re Bezeichner. Der Schema-Compiler muss die in Java nicht erlaubten Bezeichner aller- dings nach Möglichkeit korrekt auflösen. Wir wollen die bisherige Enumeration etwas erweitern, um einige Auswirkungen bei der Namensauflösung zu beobachten. Das Beispielschema sieht dann wie folgt aus.           160
    • 5.4 XML-Bezeichner anpassen                               Die Enumeration  definiert hier verschiedene gültige Bezeichner für Konto- typen. Es werden in diesem Datentyp verschiedene Notationen für die Kontotypen einge- führt, die alle eines gemeinsam haben: Sie sind als Java-Bezeichner nicht zu gebrauchen. Der Schema-Compiler versucht dennoch, aus diesen XML-Bezeichnern sinnvolle Java- Bezeichner zu erzeugen. Die Enumeration wird wie folgt als Java-Enumeration abgebildet.                           161
    • 5 XML-Schema zu Java              Zunächst fällt auf, dass die Enumeration jetzt den Namen  trägt. Wir haben hier statt der Unterstrichanpassung aus dem letzten Abschnitt eine weitere Bin- dungsdeklaration genutzt, um der Enumeration explizit einen angepassten Namen zu ge- ben.                      Mit der Bindungsdeklaration  können wir einer Enumeration also explizit einen Namen zuweisen. Etwas anderes ist in der generierten Klasse jedoch bemerkenswerter. Im Gegensatz zu der zuerst gezeigten Java-Enumeration können die Werte nicht einfach übernommen werden. Der Schema-Compiler ersetzt hier die ungültigen Zeichen -, # und . durch Unterstriche. Die ursprünglichen Werte aus dem XML-Schema werden durch Annotationen des Typs  dargestellt. Nach dem Ersetzen der unerlaubten Zeichen sind Werte wie z.B.  statt  durchaus noch erkennbar. Wir fügen jetzt noch einen Wert zu der Enumeration hinzu.       162
    • 5.4 XML-Bezeichner anpassen         Der Schema-Compiler bricht nun mit der folgenden Fehlermeldung ab:   Diesen Bezeichner kann der Schema-Compiler nämlich nicht mit seiner Standardstrategie zur Namensauflösung in einen sinnvollen Java-Bezeichner umwandeln. Der XML-Wert für dieses Enumerationselement beginnt mit einer Ziffer, was in XML durchaus gültig, in Java jedoch nicht erlaubt ist. Die Fehlermeldung gibt aber schon einen Hinweis darauf, wie dieses Problem durch eine Bindungskonfiguration gelöst werden kann. Mit der Bindungsdeklaration  kann mit dem Attribut  ein angepasster Name für einen einzelnen Enumerationswert vergeben werden. Diese Bin- dungsdeklaration können wir also genau für unser Problem verwenden. Die folgende Bin- dungskonfiguration ersetzt den problematischen Wert  durch einen gül- tigen Bezeichner. Die entsprechende Bindungsdeklaration  wird dabei in das schon existierende Element  eingefügt.                        Diese Bindungskonfiguration führt zu der folgenden Klasse .    163
    • 5 XML-Schema zu Java                                       Hinweis Die Bindungsdeklaration  kann auch direkt an einem Enu- merationswert definiert werden statt verschachtelt in einer - Deklaration. Dieses Vorgehen ist in der Referenz ausführlicher beschrieben. Globale Einstellungen für Enumerationen Neben diesen Anpassungen auf der Ebene einzelner Enumerationswerte können wir auch auf globaler Ebene das Verhalten des Schema-Compilers bei ungültigen Bezeichnern kon- figurieren. Generell wird bei ungültigen Bezeichnern in Enumerationen eine Fehlermel- dung durch den Schema-Compiler ausgegeben, wie wir bereits oben gesehen haben. Diese Einstellung entspricht der folgenden globalen Bindungsdeklaration:  164
    • 5.4 XML-Bezeichner anpassen Es kann aber sein, dass wir keine Fehlermeldung generieren wollen, z.B. weil Enumerati- onswerte für das XML-Schema dynamisch erzeugt werden und ein Abbruch des Schema- Compilers nicht erwünscht ist. Die obige Bindungsdeklaration kann hierfür auf den Wert  gesetzt werden.  In diesem Fall werden für die Enumeration Bezeichner nach dem folgenden Schema gene- riert:                                          Hier werden die Bezeichner also einfach durchnummeriert und mit dem Präfix  ver- sehen. Durch eine solche globale Bindungsdeklaration können automatisch kompilierbare Klassen generiert werden, auch wenn das XML-Schema ungültige Enumerations- Bezeichner enthält. 165
    • 5 XML-Schema zu Java 5.4.5 Verwenden von Java-Schlüsselwörtern als Bezeichner Ein weiteres Problem, das bei der Transformation von XML-Bezeichnern in Java- Bezeichner auftreten kann, sind die Java-Schlüsselwörter. Wie jede Programmiersprache reserviert auch Java bestimmte Wörter als Schlüsselwörter, z.B. das Wort  als Be- zeichner für Klassen,  als Basisdatentyp, primitive Datentypen wie ,  und viele mehr. Diese Schlüsselwörter können in einem XML-Dokument gültige Bezeichner darstellen. In den generierten Java-Klassen können wir diese Schlüsselwörter nicht als Bezeichner ver- wenden. Wir wollen uns daher an einigen Beispielen ansehen, wie JAXB mit diesem Prob- lem umgeht. Dazu nehmen wir wieder eine kleine Erweiterung unseres Schemas vor.                                               166
    • 5.4 XML-Bezeichner anpassen     Oben haben wir dem Schema einen weiteren Datentyp  erweitert, der vom bestehenden Datentyp  ableitet. Wir haben zu diesem Typ wahllos einige Attribu- te hinzugefügt, die einen Bezeichner tragen, der einem Schlüsselwort in Java entspricht. Alle drei Bezeichner kommen als Variablennamen in Java nicht in Frage. Aus diesem Da- tentyp erzeugt der Schema-Compiler eine Klasse, die aufgrund unserer vorher definierten Benennungsstrategie den Namen  trägt. Wir starten den Schema-Compiler hier wieder mit der folgenden Bindungskonfiguration.                       Die generierte Klasse sieht nun folgendermaßen aus:                    Wir sehen hier zwei Strategien, die der Schema-Compiler zur Umbenennung der Schlüs- selwörter verfolgt. 167
    • 5 XML-Schema zu Java Die Bezeichner  und  werden jeweils mit Unterstrichen als Präfix versehen, während der Bezeichner  in  umbenannt wird. Wir sehen also, dass der Sche- ma-Compiler nach bestem Wissen und Gewissen versucht, kompilierbaren Code zu erzeu- gen, falls keine benutzerdefinierten Anpassungen durch Bindungsdeklarationen angegeben werden. 5.4.6 Java-Namenskonventionen Eingangs haben wir bereits die ungeschriebenen Konventionen für die Namensgebung von Bezeichnern in Java erwähnt. Standardmäßig versucht der Schema-Compiler, Bezeichner gemäß dieser Konventionen zu generieren. Die dafür zuständige Bindungsdeklaration  ist daher standardmäßig auf den Wert  ge- setzt. Wenn wir jedoch strikt die Bezeichner aus dem XML-Schema in Java umsetzen wollen, können wir dieses Verhalten auch außer Kraft setzen. Da dies aber eher selten ist, verwei- sen wir hier für nähere Informationen auf das Referenzkapitel. 5.4.7 Zusammenfassung Java besitzt im Vergleich zu XML wesentlich strengere Konventionen zur Namensge- bung. Dadurch ergeben sich häufig Namenskonflikte bei der Erzeugung von Java- Klassen aus einem XML-Schema. Der Schema-Compiler besitzt Standardstrategien zur Auflösung von Namenskonflik- ten. Mit  lassen sich bequem schemaweite Namenspräfixe und - suffixe für die XML-Bezeichner vergeben. Enumerationen sind häufig Quelle von Namenskonflikten, da sie in XML freier defi- niert werden können als in Java. Mit   und  lassen sich Bezeichner in Enumerationen anpassen. Setzen wir die globale Einstellung  auf , werden die Java Naming Conventions vom Schema-Compiler nicht beachtet, aber das ist eine der eher verdächtigen Optionen ... 5.5 Datentypen anpassen Wenn es um Datentypen geht, treffen mit Java und XML-Schema zwei recht unterschied- liche Welten aufeinander. XML-Schema bietet einige vordefinierte Datentypen, die so nicht in Java auftauchen. Viel wichtiger noch, mit den simpleType-Deklarationen und de- 168
    • 5.5 Datentypen anpassen ren Einschränkungen durch Facets lassen sich sehr komplexe Datentypen aufbauen, die keine Entsprechung in Java finden. Die Qual der Wahl bei der Abbildung auf Java-Datentypen nimmt uns der Schema- Compiler normalerweise mit Standardeinstellungen ab. In diesem Abschnitt sehen wir, wie eine Bindungskonfiguration helfen kann, wenn die vom Schema-Compiler gewählten Standarddatentypen unseren Anforderungen nicht gerecht werden. 5.5.1 Datentypen explizit angeben mit jaxb:baseType Eine einfache Möglichkeit der Anpassung von Datentypen bietet die Bindungsdeklaration . Diese Bindungsdeklaration kann auf zwei Arten innerhalb des bereits bekannten -Elements definiert werden. Eine Definition auf anderer Ebene ist nicht möglich. Als Beispiel werden wir hier das Kundenelement  unseres   Schemas verwenden. Typen angeben mit dem name-Attribut    Mit dieser Variante können wir den standardmäßig für dieses Element gewählten Typ ge- neralisieren oder spezialisieren. Wichtig ist, dass die angegebene Klasse in der Verer- bungshierarchie des Standardtypen liegt. Generalisieren Ein Beispiel für eine Generalisierung ist die folgende Bindungskonfiguration.               Das obige Beispiel definiert den Basistypen  für das Kundenelement . Da  die Basisklasse aller Objekte darstellt, ist es damit theoretisch mög- lich, der Eigenschaft  unserer -Klasse ein beliebiges Objekt zuzuwei- sen. Der Schema-Compiler erzeugt nämlich mit dieser Bindungskonfiguration folgende Klasse: 169
    • 5 XML-Schema zu Java                       Wie wir sehen, wurde die Eigenschaft  als Eigenschaft vom Typ   angelegt. Falls die konkrete Implementierungsklasse hier noch offen bleiben soll, kann diese Bindungsdeklaration genutzt werden. Eine Sache fällt aber noch auf: Die Annotation  gibt als Typ für die Eigenschaft immer noch die Klasse  an. Dies dient dazu, dass beim Unmarshalling eines XML-Dokuments, das kein -Attribut für das Element  ausweist, trotzdem noch in die Standard- klasse  transformiert werden kann. Auch beim Marshalling erwartet die JAXB-Implementierung hier übrigens immer noch eine Customer-Instanz, alles andere provoziert Ausnahmen. Spezialisieren Auf der anderen Seite können wir natürlich auch den genau umgekehrten Effekt erreichen, indem wir unter  eine Klasse angeben, die von unserer -Klasse ableitet, also eine Spezialisierung darstellt. Dies könnte der Fall sein, wenn benutzerdefinierte Klassen existieren, die weitere Eigenschaften besitzen, die aber nicht an eine XML- Darstellung gebunden werden. Oder aber wir möchten ein Schema allgemein definieren, es jedoch durch Bindungskonfigurationen spezialisieren können. Erweitern wir hierzu unser Kundenschema  um einen Geschäftskunden, der alle Eigenschaften des normalen Kundentyps erbt, zusätzlich aber noch eine Geschäftsnummer besitzt, unter der die Firma registriert ist. Das so erweiterte Schema sieht dann so aus.         170
    • 5.5 Datentypen anpassen                              Im -Schema ist der Kunde weiterhin mit dem allgemeineren Datentyp  angegeben.          Mit der Bindungsdeklaration  können wir jetzt, ohne das Schema verändern zu müssen, den Kunden zu einem Geschäftskunden machen. Dazu weisen wir ihm den Typ  zu.                171
    • 5 XML-Schema zu Java Diese Bindungskonfiguration führt nun dazu, dass die Java-Klasse  auf den spe- zialisierten Typ  verweist. Unser -XML-Schema ist dabei aber gleich geblieben.                        Die manuelle Konfiguration der in Java verwendeten Datentypen ist eine recht sensible Angelegenheit. Leicht entstehen durch solche Konfigurationen Ausnahmen vom Typ  beim Marshalling oder Unmarshalling. Hinweis Ein weiterer, sehr beliebter Anwendungsfall für die Spezialisierung sind Elemente vom Typ , die Referenzen auf andere Elemente darstellen. Diese Referenzen werden norma- lerweise als Eigenschaften vom Typ  generiert. Um hier die Typbin- dung zu verstärken, kann als Spezialisierung die Klasse des referenzierten Elements angege- ben werden. Das praktische Vorgehen für diesen Fall ist in der Referenz beschrieben. Typen konvertieren mit dem jaxb:javaType-Element      Die zweite Möglichkeit der Definition von Datentypen ist die Angabe einer -Bindungsdeklaration innerhalb der -Deklaration. Mit dieser Deklaration können für Java-Eigenschaften Datentypen jenseits der Standardabbil- dung von XML nach Java konfiguriert werden. Wie dies genau funktioniert, sehen wir im nächsten Abschnitt. 172
    • 5.5 Datentypen anpassen 5.5.2 Datentypen konvertieren mit jaxb:javaType Bisher wird in unserem -Schema der Typ  auf einen  ab- gebildet, während die Typen  und  als Kommazahlen auf die Klasse   abgebildet werden.             Datentypen global konvertieren In den Systemen, die wir mit dem Online-Banking-Service bedienen, wird vielleicht mit anderen Datentypen gearbeitet. So wird die Kontonummer dort z.B. durch den Ganzzahl- typ  repräsentiert, weil es gar nicht so viele Konten gibt. Bei der einen oder anderen Schweizer Privatbank mögen eventuell sogar -basiert