Leitfaden für JAXB

** 1. Einführung

**

Dies ist ein einleitender Artikel zu JAXB (Java Architecture for XML Binding).

Zuerst wird gezeigt, wie Java-Objekte in XML und umgekehrt konvertiert werden. Anschließend werden wir uns darauf konzentrieren, Java-Klassen aus einem XML-Schema zu generieren und umgekehrt, indem Sie das JAXB-2 Maven-Plugin verwenden.

2. Überblick

JAXB bietet eine schnelle und bequeme Möglichkeit, Java-Objekte in XML zu marshallieren (zu schreiben) und XML in Objekte zu deklarieren (lesen). Es unterstützt ein Bindungsframework, das XML-Elemente und Attribute Java-Feldern und Eigenschaften mithilfe von Java-Anmerkungen zuordnet.

Das JAXB-2 Maven-Plugin delegiert den Großteil seiner Arbeit an eines der beiden von JDK bereitgestellten Tools XJC und http ://docs.oracle.com/javase/7/docs/technotes/tools/share/schemagen.html[Schemagen].

3. JAXB-Anmerkungen

JAXB verwendet Java-Anmerkungen, um die generierten Klassen um zusätzliche Informationen zu erweitern. Das Hinzufügen solcher Anmerkungen zu vorhandenen Java-Klassen bereitet sie auf die JAXB-Laufzeit vor.

Lassen Sie uns zunächst ein einfaches Java-Objekt erstellen, um das Rangieren und Nicht-Rangieren zu veranschaulichen:

@XmlRootElement(name = "book")
@XmlType(propOrder = { "id", "name", "date" })
public class Book {
    private Long id;
    private String name;
    private String author;
    private Date date;

    @XmlAttribute
    public void setId(Long id) {
        this.id = id;
    }

    @XmlElement(name = "title")
    public void setName(String name) {
        this.name = name;
    }

    @XmlTransient
    public void setAuthor(String author) {
        this.author = author;
    }

   //constructor, getters and setters
}

Die obige Klasse enthält die folgenden Anmerkungen:

  • Der Name des XML-Stammelements wird vom Klassennamen und von we abgeleitet

kann auch den Namen des Wurzelelements der XML anhand seines Namens angeben Attribut @ XmlType ** : Definiert die Reihenfolge, in der die Felder in geschrieben werden

XML-Datei @ XmlElement ** : Definiert den tatsächlichen Namen des XML-Elements

  • Definiere, dass das ID-Feld anstelle eines Elements als Attribut zugeordnet ist

  • Anmerkungsfelder, die nicht in XML aufgenommen werden sollen

Weitere Informationen zur JAXB-Anmerkung finden Sie unter http://docs.oracle.com/javaee/7/api/javax/xml/bind/annotation/package-summary.html ().

4. Marshalling

Marshalling bietet einer Clientanwendung die Möglichkeit, eine von JAXB abgeleitete Java-Objektstruktur in XML-Daten zu konvertieren. Standardmäßig verwendet der Marshaller beim Generieren von XML-Daten die UTF-8-Codierung. Als Nächstes generieren wir XML-Dateien aus Java-Objekten.

Erstellen wir ein einfaches Programm mit JAXBContext , das eine Abstraktion für die Verwaltung der XML/Java-Bindungsinformationen bereitstellt, die zum Implementieren der JAXB-Bindungsframeworkoperationen erforderlich sind:

public void marshal() throws JAXBException, IOException {
    Book book = new Book();
    book.setId(1L);
    book.setName("Book1");
    book.setAuthor("Author1");
    book.setDate(new Date());

    JAXBContext context = JAXBContext.newInstance(Book.class);
    Marshaller mar= context.createMarshaller();
    mar.setProperty(Marshaller.JAXB__FORMATTED__OUTPUT, Boolean.TRUE);
    mar.marshal(book, new File("./book.xml"));
}

Die Klasse javax.xml.bind.JAXBContext bietet einen Einstiegspunkt eines Clients für die JAXB-API. Standardmäßig formatiert JAXB das XML-Dokument nicht. Dies spart Platz und verhindert, dass Leerräume versehentlich als signifikant interpretiert werden.

Damit JAXB die Ausgabe formatiert, setzen wir die Marshaller.JAXB FORMATTED OUTPUT -Eigenschaft des Marshaller auf true . Die Marshall-Methode verwendet ein Objekt und eine Ausgabedatei, in der das generierte XML als Parameter gespeichert wird.

Wenn wir den obigen Code ausführen, überprüfen wir möglicherweise das Ergebnis in book.xml , um sicherzustellen, dass das Java-Objekt erfolgreich in XML-Daten konvertiert wird:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<book id="1">
    <title>Book1</title>
    <date>2016-11-12T11:25:12.227+07:00</date>
</book>

5. Rangieren

Beim Marshalling kann eine Clientanwendung XML-Daten in JAXB-abgeleitete Java-Objekte konvertieren.

Lassen Sie uns JAXB Unmarshaller verwenden, um unsere book.xml wieder in ein Java-Objekt zu dekomprimieren:

public Book unmarshall() throws JAXBException, IOException {
    JAXBContext context = JAXBContext.newInstance(Book.class);
    return (Book) context.createUnmarshaller()
      .unmarshal(new FileReader("./book.xml"));
}

Wenn Sie den obigen Code ausführen, überprüfen wir möglicherweise die Konsolenausgabe, um sicherzustellen, dass wir XML-Daten erfolgreich in ein Java-Objekt konvertiert haben:

Book[id=1, name=Book1, author=null, date=Sat Nov 12 11:38:18 ICT 2016]----

===  **  6. **  Komplexe Datentypen

Beim Umgang mit komplexen Datentypen, die in JAXB möglicherweise nicht direkt verfügbar sind, schreiben wir möglicherweise einen Adapter, um JAXB mitzuteilen, wie ein bestimmter Typ verwaltet wird.

Mit dem __XmlAdapter__ von JAXB können wir einen benutzerdefinierten Code definieren, um eine nicht zuzuordnende Klasse in etwas zu konvertieren, das JAXB verarbeiten kann. Die Annotation __ @ XmlJavaTypeAdapter__ verwendet einen Adapter, der die Klasse __XmlAdapter__ für benutzerdefiniertes Marshalling erweitert.

Lassen Sie uns einen Adapter erstellen, um beim Marshalling ein Datumsformat anzugeben:

[source,java,gutter:,true]

public class DateAdapter extends XmlAdapter<String, Date> {

private static final ThreadLocal<DateFormat> dateFormat
  = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
};
@Override
public Date unmarshal(String v) throws Exception {
    return dateFormat.get().parse(v);
}
    @Override
    public String marshal(Date v) throws Exception {
        return dateFormat.get().format(v);
    }
}
Wir verwenden das Datumsformat "__yyyy-MM-dd HH: mm: ss__", um __Date__ beim Marshalling in __String__ zu konvertieren und __ThreadLocal__, um unseren __DateFormat__-Thread sicher zu machen.

Wenden wir den __DateAdapter__ auf unser __Book__ an:

[source,java,gutter:,true]

@XmlRootElement(name = "book") @XmlType(propOrder = { "id", "name", "date" }) public class Book { private Long id; private String name; private String author; private Date date;

@XmlAttribute
public void setId(Long id) {
    this.id = id;
}
@XmlTransient
public void setAuthor(String author) {
    this.author = author;
}
@XmlElement(name = "title")
public void setName(String name) {
    this.name = name;
}
    @XmlJavaTypeAdapter(DateAdapter.class)
    public void setDate(Date date) {
        this.date = date;
    }
}
Wenn wir den obigen Code ausführen, überprüfen wir möglicherweise das Ergebnis in __book.xml__, um sicherzustellen, dass wir unser Java-Objekt erfolgreich in XML konvertiert haben, und zwar mit dem neuen Datumsformat „__yyyy-MM-dd HH: mm: ss__“:

[source,xml,gutter:,true]

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <book id="1"> <title>Book1</title> <date>2016-11-10 23:44:18</date>final </book>

===  **  7. JAXB-2 Maven Plugin

**

Dieses Plugin verwendet die Java-API für XML-Bindung (JAXB), Version 2, um Java-Klassen aus XML-Schemas (und optional Bindungsdateien) zu generieren oder ein XML-Schema aus einer kommentierten Java-Klasse zu erstellen.

Beachten Sie, dass es zwei grundlegende Ansätze für die Erstellung von Web-Services gibt, __Contract Last__ und __Contract First__. Weitere Informationen zu diesen Ansätzen erhalten Sie unter http://docs.spring.io/spring-ws/site/reference/html/why-contract-first.html[link].

====  **  7.1. Java-Klasse aus XSD generieren **

Das JAXB-2 Maven-Plugin verwendet das von JDK bereitgestellte Tool XJC, ein JAXB Binding-Compiler-Tool, das Java-Klassen aus XSD (XML-Schema-Definition) generiert.

Erstellen wir eine einfache __user.xsd__ -Datei und verwenden Sie das JAXB-2-Maven-Plugin, um Java-Klassen aus diesem XSD-Schema zu generieren:

[source,xml,gutter:,true]

<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="/jaxb/gen" xmlns:userns="/jaxb/gen" elementFormDefault="qualified">

<element name="userRequest" type="userns:UserRequest"></element>
<element name="userResponse" type="userns:UserResponse"></element>
<complexType name="UserRequest">
    <sequence>
        <element name="id" type="int"/>
        <element name="name" type="string"/>
    </sequence>
</complexType>
    <complexType name="UserResponse">
        <sequence>
            <element name="id" type="int"/>
            <element name="name" type="string"/>
            <element name="gender" type="string"/>
            <element name="created" type="dateTime"/>
        </sequence>
    </complexType>
</schema>
Lassen Sie uns das JAXB-2 Maven Plugin konfigurieren:

[source,xml,gutter:,true]

<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>2.3</version> <executions> <execution> <id>xjc</id> <goals> <goal>xjc</goal> </goals> </execution> </executions> <configuration> <xjbSources> <xjbSource>src/main/resources/global.xjb</xjbSource> </xjbSources> <sources> <source>src/main/resources/user.xsd</source> </sources> <outputDirectory>${basedir}/src/main/java</outputDirectory> <clearOutputDir>false</clearOutputDir> </configuration> </plugin>

Dieses Plugin sucht standardmäßig nach XSD-Dateien in __src/main/xsd__. Wir können die XSD-Suche konfigurieren, indem Sie den Konfigurationsabschnitt dieses Plugins in der Datei __pom.xml__ entsprechend ändern.

Standardmäßig werden diese Java-Klassen im Ordner __target/generated-resources/jaxb__ generiert. Wir können das Ausgabeverzeichnis ändern, indem Sie der Plug-In-Konfiguration ein __outputDirectory__ -Element hinzufügen. Wir können auch ein __clearOutputDir__ -Element mit dem Wert false hinzufügen, um zu verhindern, dass die Dateien in diesem Verzeichnis gelöscht werden.

Wir können auch eine globale JAXB-Bindung konfigurieren, die die Standardbindungsregeln überschreibt:

[source,xml,gutter:,true]

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema" jaxb:extensionBindingPrefixes="xjc">

    <jaxb:globalBindings>
        <xjc:simple/>
        <xjc:serializable uid="-1"/>
        <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
            parse="javax.xml.bind.DatatypeConverter.parseDateTime"
            print="javax.xml.bind.DatatypeConverter.printDateTime"/>
    </jaxb:globalBindings>
</jaxb:bindings>
Das oben angegebene __global.xjb__ überschreibt den __dateTime__-Typ mit dem __java.util.Calendar__-Typ. Wenn wir das Projekt erstellen, werden Klassendateien im Ordner __src/main/java__ und im Paket __com.baeldung.jaxb.gen__ generiert.

====  **  7.2. XSD-Schema aus Java generieren **

Dasselbe Plugin verwendet das von JDK bereitgestellte Werkzeug __Schemagen__. Dies ist ein JAXB Binding-Compiler-Tool, das ein XSD-Schema aus Java-Klassen erstellen kann.

Damit eine Java-Klasse für einen XSD-Schemankandidaten in Frage kommt, muss die Klasse mit einer Annotation __ @ XmlType__ versehen werden.

Wir verwenden die Java-Klassendateien aus dem vorherigen Beispiel wieder. Lassen Sie uns das Plugin konfigurieren:

[source,xml,gutter:,true]

<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>2.3</version> <executions> <execution> <id>schemagen</id> <goals> <goal>schemagen</goal> </goals> </execution> </executions> <configuration> <sources> <source>src/main/java/com/baeldung/jaxb/gen</source> </sources> <outputDirectory>src/main/resources</outputDirectory> <clearOutputDir>false</clearOutputDir> <transformSchemas> <transformSchema> <uri>/jaxb/gen</uri> <toPrefix>user</toPrefix> <toFile>user-gen.xsd</toFile> </transformSchema> </transformSchemas> </configuration> </plugin>

Standardmäßig durchsucht JAXB alle Ordner unter __src/main/java__ rekursiv nach kommentierten JAXB-Klassen. Wir können einen anderen __source__-Ordner für unsere mit Anmerkungen versehenen JAXB-Klassen angeben, indem Sie der Plug-In-Konfiguration ein __source__ -Element hinzufügen.

Wir können auch einen __transformSchemas__ registrieren, einen Postprozessor, der für die Benennung des XSD-Schemas verantwortlich ist. Es funktioniert, indem der __namespace__ mit dem Namespace des __ @ XmlType__ Ihrer Java-Klasse abgeglichen wird.

Beim Erstellen des Projekts wird eine __user-gen.xsd__ -Datei im Verzeichnis __src/main/resources__ erstellt.

===  **  8. **  **  Schlussfolgerung **

In diesem Artikel haben wir Einführungskonzepte zu JAXB behandelt. Einzelheiten finden Sie auf der http://www.oracle.com/technetwork/articles/javase/index-140168.html[JAXB-Startseite].

Den Quellcode für diesen Artikel finden Sie unter https://github.com/eugenp/tutorials/tree/master/jaxb