Java-XML-Mapping mit JAXB 2.0 ganz einfach

Die Java-Architektur für XML-Bindung bietet eine leistungsstarke und praktische Möglichkeit, mit XML-Inhalten in Java-Anwendungen zu arbeiten. Das neu veröffentlichte JAXB 2.0 bietet viele neue Funktionen, einschließlich der vollständigen Unterstützung aller XML-Schema-Funktionen, deutlich weniger generierter Klassen, generierter Klassen, die einfacher zu bearbeiten sind, und eines flexibleren Validierungsmechanismus.

Um zu verstehen, wie XML-Dokumente in Java mit JAXB 2.0 verarbeitet werden, müssen wir uns die beiden Hauptkomponenten von JAXB ansehen:

  • Der Bindungscompiler, der ein bestimmtes XML-Schema an eine Reihe generierter Java-Klassen bindet
  • Das verbindliche Laufzeitframework, das Funktionen zum Unmarshalling, Marshalling und zur Validierung bereitstellt

Mit dem JAXB-Bindungscompiler (oder xbj) können Sie Java-Klassen aus einem bestimmten XML-Schema generieren. Der JAXB-Bindungscompiler wandelt ein XML-Schema in eine Sammlung von Java-Klassen um, die der im XML-Schema beschriebenen Struktur entsprechen. Diese Klassen werden mit speziellen JAXB-Annotationen versehen, die dem Laufzeitframework die Zuordnungen bereitstellen, die es zur Verarbeitung der entsprechenden XML-Dokumente benötigt.

Das Bindungslaufzeit-Framework bietet einen effizienten und benutzerfreundlichen Mechanismus zum Aufheben des Marshalling (oder Lesens) und Marshalling (oder Schreibens) von XML-Dokumenten. Sie können ein XML-Dokument in eine Hierarchie von Java-Objekten umwandeln (Unmarshalling) oder umgekehrt eine Java-Objekthierarchie in ein XML-Format umwandeln (Marshalling). Der Begriff Rangieren bezieht sich traditionell auf die Entsorgung von Truppen auf geeignete Weise. Im Netzwerk bezieht es sich auf das Platzieren von Datenelementen in einem Puffer, bevor sie über einen Kommunikationskanal gesendet werden.

Zusammen ergeben diese beiden Komponenten eine Technologie, mit der Java-Entwickler XML-Daten einfach in Form von Java-Objekten bearbeiten können, ohne die Details der einfachen API für die XML-Verarbeitung (SAX) oder des Document Object Model (DOM) kennen zu müssen. oder sogar die Feinheiten des XML-Schemas.

JAXB-Voraussetzungen

Um mit JAXB 2.0 zu beginnen, benötigen Sie:

  • Java Platform, Standard Edition 5: JAXB 2.0 stützt sich stark auf Funktionen von Java SE 5 wie Anmerkungen und Generika
  • Eine Implementierung von JAXB 2.0

Dieser Artikel wurde mit dem Release-Kandidaten für die GlassFish JAXB-Referenzimplementierung geschrieben.

Generieren Sie Java-Klassen mit dem JAXB-Compiler

Der JAXB-Compiler bindet ein XML-Schema an eine Reihe von Java-Klassen. Ein XML-Schema ist ein XML-Dokument, das die in einem bestimmten XML-Dokumenttyp autorisierten Elemente und Attribute sehr genau beschreibt. In diesem Beispiel verwenden wir ein Schulungsbuchungssystem, das Bestellungen im XML-Format annehmen kann. Eine typische Bestellung sieht folgendermaßen aus:

    10 Coyote Avenue, Arizona, USA     

Das entsprechende XML-Schema beschreibt, wie der Schulungskurs gebucht wird, und enthält Details zum gebuchten Kurs, den eingeschriebenen Studenten, dem Unternehmen, das die Buchung vornimmt usw. Eine XML-Schemabeschreibung ist äußerst streng und kann Details wie die Anzahl der in einer Liste von Objekten zulässigen Elemente (Kardinalität), optionale und obligatorische Attribute und mehr enthalten. Das Schema für die Schulungsbuchungen (aufgerufen course-booking.xsd) wird hier gezeigt:

Das Befehlszeilentool xjcführt den JAXB-Compiler aus. Um den JAXB-Compiler für unser Schema auszuführen, führen Sie den folgenden Befehl aus:

 $xjc course-booking.xsd -p nz.co.equinox.training.domain.booking -d src/generated

Dadurch wird eine Reihe von Java-Klassen generiert, die mit JAXB 2.0-Annotationen versehen sind. Einige der nützlicheren Optionen werden hier beschrieben:

  • -d : Legen Sie die generierten Dateien in diesem Verzeichnis ab.
  • -p : Platzieren Sie die generierten Dateien in diesem Paket.
  • -nv: Führen Sie keine strikte Überprüfung des Eingabeschemas durch.
  • -httpproxy : Verwenden Sie diese Option, wenn Sie sich hinter einem Proxy befinden. Nimmt das Format an [user[:password]@]proxyHost[:proxyPort].
  • -classpath : Geben Sie ggf. den Klassenpfad an.
  • -readOnly: Generiert schreibgeschützte Quellcodedateien, wenn Ihr Betriebssystem dies unterstützt.

Es gibt auch eine äquivalente antAufgabe, die die Integration in einen Ant- oder Maven-basierten Build-Prozess recht einfach macht.

Die Liste der generierten Klassen wird hier angezeigt:

 CompanyType.java ContactType.java CourseBooking.java ObjectFactory.java StudentType.java

Benutzer früherer Versionen von JAXB stellen möglicherweise fest, dass es sich um eine übersichtliche Gruppe kommentierter und vollständig dokumentierter Java-Klassen handelt und nicht um die umständlicheren Schnittstellen und Implementierungen früherer Versionen. Daher haben wir weniger generierte Klassen und leichteren und eleganteren Code. Und wie Sie im nächsten Abschnitt sehen werden, ist die Bearbeitung dieser Klassen einfach.

Aufheben der Bereitstellung eines XML-Dokuments

Beim Unmarshalling wird ein XML-Dokument in einen entsprechenden Satz von Java-Objekten konvertiert. Das Unmarshalling in JAXB 2.0 ist einfach. Zunächst erstellen Sie ein JAXBContextKontextobjekt. Das Kontextobjekt ist der Ausgangspunkt für Marshalling-, Unmarshalling- und Validierungsoperationen. Hier geben Sie das Java-Paket an, das Ihre JAXB-zugeordneten Klassen enthält:

 JAXBContext jaxbContext = JAXBContext.newInstance ("nz.co.equinox.training.domain.booking");

Um die Bereitstellung eines XML-Dokuments aufzuheben, erstellen Sie ein Dokument Unmarshalleraus dem Kontext, wie hier gezeigt:

 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

Sie unmarshallerkönnen XML-Daten aus einer Vielzahl von Datenquellen verarbeiten: Dateien, Eingabestreams, URLs, DOM-Objekte, SAX-Parser und mehr. Hier stellen wir ein einfaches FileObjekt zur Verfügung, das auf unser XML-Dokument verweist. Das unmarshallergibt einen JAXBElementTyp zurück , von dem wir unser nicht gemarshalltes Objekt mithilfe der folgenden getValue()Methode erhalten können:

JAXBElement bookingElement = (JAXBElement) unmarshaller.unmarshal( new File("src/test/resources/xml/booking.xml"));

CourseBooking booking = bookingElement.getValue();

Dokumentenvalidierung

Bei der Dokumentvalidierung wird sichergestellt, dass Ihr XML-Dokument der im entsprechenden XML-Schema angegebenen Definition entspricht. Dies ist ein wichtiger Aspekt jedes Projekts, das den XML-Austausch umfasst, insbesondere wenn das XML von anderen Systemen stammt. Die Dokumentvalidierung in JAXB 2.0 ist einfacher und flexibler als in früheren Versionen. Sie können einfach ein ValidatonEventHandleran unmarshallerdas XML-Dokument anhängen , bevor Sie die Bereitstellung aufheben, wie hier gezeigt:

 unmarshaller.setEventHandler(new BookingValidationEventHandler());

Ein Validierungsereignishandler implementiert die ValidationEventHandlerSchnittstelle und die handleEvent()Methode wie hier gezeigt:

public class BookingValidationEventHandler implements ValidationEventHandler{

public boolean handleEvent(ValidationEvent ve) {

if (ve.getSeverity()==ValidationEvent.FATAL_ERROR || ve .getSeverity()==ValidationEvent.ERROR){ ValidationEventLocator locator = ve.getLocator(); //Print message from valdation event System.out.println("Invalid booking document: " + locator.getURL()); System.out.println("Error: " + ve.getMessage()); //Output line and column number System.out.println("Error at column " + locator.getColumnNumber() + ", line " + locator.getLineNumber()); } return true; } }

Here we just print details of the error, but in a real application, some less trivial treatment might be appropriate. In some cases, you may even consider that the validation error is not a show-stopper and that it will not block the processing. By returning true, you tell the unmarshaller to continue the unmarshalling process: false would terminate the process with an appropriate exception.

Marshalling a document

Marshalling involves transforming your Java classes into XML format. In JAXB 2.0, creating and manipulating these Java classes is simple. In most cases, you can just treat them like ordinary Java classes, as shown here:

 CourseBooking booking = new CourseBooking(); booking.setCourseReference("UML-101"); booking.setTotalPrice(new BigDecimal(10000)); ...

Note that you can still use the ObjectFactory class similarly to how you used it in JAXB 1.0, as shown in the following listing. However, unlike JAXB 1.0, there are no interfaces or implementation classes: all domain objects are just annotated JavaBeans components.

 ObjectFactory factory = new ObjectFactory(); CourseBooking booking = factory.createCourseBooking(); ...

Although most XML data types map directly to normal Java classes, some special treatment is needed for certain data types, such as dates. In these cases, you must use the DatatypeFactory, as shown here:

 DatatypeFactory datatypes = DatatypeFactory.newInstance(); booking.setCourseDate(datatypes.newXMLGregorianCalendarDate(2006,06,15,0));

Once your domain object is initialized, use the JAXB context to create a Marshaller object and a typed JAXBElement. Creating the marshaller is simple:

 Marshaller marshaller = jaxbContext.createMarshaller();

Als Nächstes erstellen Sie ein JAXBElementObjekt, das Ihr Domänenobjekt kapselt. Die Eingabe JAXBElemententspricht dem Stammelement complexTypeIhres XML-Dokuments. Verwenden Sie dann die generierte ObjectFactoryKlasse wie folgt:

 JAXBElement bookingElement = (new ObjectFactory()).createBooking(booking);

In diesem Beispiel legen wir eine Eigenschaft fest, damit die Ausgabe für den menschlichen Gebrauch formatiert wird, und schreiben dann in die Standardausgabe:

 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); marshaller.marshal( bookingElement, System.out );

Ein vollständiges Codebeispiel finden Sie hier:

JAXBContext jaxbContext = JAXBContext.newInstance("nz.co.equinox.training.domain.booking");

CourseBooking booking = new CourseBooking(); booking.setCourseReference("UML-101"); booking.setTotalPrice(new BigDecimal(10000)); booking.setInvoiceReference("123456"); DatatypeFactory datatypes = DatatypeFactory.newInstance(); booking.setCourseDate(datatypes.newXMLGregorianCalendarDate(2006,06,15,0)); booking.setTotalPrice(new BigDecimal(10000)); booking.setInvoiceReference("123456"); booking.getStudent().add(new StudentType()); booking.getStudent().get(0).setFirstName("John"); booking.getStudent().get(0).setSurname("Smith"); booking.setCompany(new CompanyType()); booking.getCompany().setName("Clients inc."); booking.getCompany().setContact(new ContactType()); booking.getCompany().getContact().setName("Paul"); booking.getCompany().getContact().setEmail("[email protected]"); booking.getCompany().getContact().setTelephone("12345678"); booking.getCompany().setAddress("10 client street");

// Marshal to System.out Marshaller marshaller = jaxbContext.createMarshaller(); JAXBElement bookingElement = (new ObjectFactory()).createBooking(booking); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

marshaller.marshal( bookingElement, System.out );

Wenn Sie diesen Code ausführen, wird Folgendes generiert: