Guide de JAXB

** 1. Introduction

**

Ceci est un article d’introduction sur JAXB (Java Architecture for XML Binding).

Tout d’abord, nous montrerons comment convertir des objets Java en XML et inversement, puis nous nous concentrerons sur la génération de classes Java à partir d’un schéma XML, et inversement, à l’aide du plugin JAXB-2 Maven.

2. Vue d’ensemble

JAXB offre un moyen rapide et pratique de marshaler (écrire) des objets Java en XML et un-marshal (lire) XML en objets. Il prend en charge une structure de liaison qui mappe des éléments et des attributs XML sur des champs et des propriétés Java à l’aide d’annotations Java.

Le plug-in JAXB-2 Maven délègue l’essentiel de son travail à l’un des deux outils fournis par JDK, XJC et http ://docs.oracle.com/javase/7/docs/technotes/tools/share/schemagen.html[Schemagen].

3. Annotations JAXB

JAXB utilise des annotations Java pour compléter les classes générées avec des informations supplémentaires. L’ajout de telles annotations aux classes Java existantes les prépare pour l’exécution de JAXB.

Commençons par créer un objet Java simple pour illustrer le triage et le dé-triage:

@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
}

La classe ci-dessus contient les annotations suivantes:

  • Le nom de l’élément XML racine est dérivé du nom de la classe et nous

peut également spécifier le nom de l’élément racine du XML en utilisant son nom attribut @ XmlType ** : définit l’ordre dans lequel les champs sont écrits dans le champ

Fichier XML @ XmlElement ** : définit le nom de l’élément XML qui sera utilisé

  • définir le champ id est mappé en tant qu’attribut au lieu d’un élément

  • annoter les champs que nous ne voulons pas inclure dans XML

Pour plus de détails sur les annotations JAXB, consultez le link

4. Marshalling

Marshalling fournit à une application cliente la possibilité de convertir une arborescence d’objets Java dérivée de JAXB en données XML. Par défaut, Marshaller utilise le codage UTF-8 lors de la génération de données XML. Ensuite, nous allons générer des fichiers XML à partir d’objets Java.

Créons un programme simple utilisant JAXBContext , qui fournit une abstraction permettant de gérer les informations de liaison XML/Java nécessaires à la mise en oeuvre des opérations du cadre de liaison JAXB:

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"));
}

La classe javax.xml.bind.JAXBContext fournit un point d’entrée du client à l’API JAXB. Par défaut, JAXB ne formate pas le document XML. Cela économise de l’espace et évite que tout espace blanc ne soit accidentellement interprété comme significatif.

Pour que JAXB formate la sortie, il suffit de définir la propriété Marshaller.JAXB FORMATTED OUTPUT sur true sur le Marshaller . La méthode marshal utilise un objet et un fichier de sortie où stocker le XML généré en tant que paramètres.

Lorsque nous exécutons le code ci-dessus, nous pouvons vérifier le résultat dans book.xml pour vérifier que nous avons converti avec succès l’objet Java en données XML:

<?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. Un-marshalling

Un-marshalling permet à une application client de convertir des données XML en objets Java dérivés de JAXB.

Utilisons JAXB Unmarshaller pour annuler le marshal de notre book.xml en un objet Java:

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

Lorsque nous exécutons le code ci-dessus, nous pouvons vérifier la sortie de la console pour vérifier que nous avons converti avec succès les données XML en objet Java:

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

===  **  6. **  Types de données complexes

Lors du traitement de types de données complexes qui peuvent ne pas être directement disponibles dans JAXB, nous pouvons écrire un adaptateur pour indiquer à JAXB comment gérer un type spécifique.

En utilisant __XmlAdapter__ de JAXB, nous pouvons définir un code personnalisé pour convertir une classe non mappable en quelque chose que JAXB peut gérer. L'annotation __ @ XmlJavaTypeAdapter__ utilise un adaptateur qui étend la classe __XmlAdapter__ pour le marshaling personnalisé.

Créons un adaptateur pour spécifier un format de date lors du marshaling:

[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);
    }
}
Nous utilisons un format de date "__yyyy-MM-jj HH: mm: ss__" pour convertir __Date__ en __String__ lors du marshalling et __ThreadLocal__ pour rendre notre __DateFormat__ thread-safe.

Appliquons le __DateAdapter__ à notre __Book__:

[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;
    }
}
Lorsque nous exécutons le code ci-dessus, nous pouvons vérifier le résultat dans __book.xml__ pour vérifier que nous avons converti avec succès notre objet Java en XML en utilisant le nouveau format de date "__yyyy-MM-jj 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

**

Ce plugin utilise l’API Java pour la liaison XML (JAXB), version 2+, pour générer des classes Java à partir de XML Schemas (et éventuellement des fichiers de liaison) ou pour créer un schéma XML à partir d’une classe Java annotée.

Notez qu'il existe deux approches fondamentales pour la création de services Web, __Contract Last__ et Contract First__. Pour plus de détails sur ces approches, consultez le http://docs.spring.io/spring-ws/site/reference/html/why-contract-first.html[link]

====  **  7.1. Générer une classe Java à partir de XSD **

Le plug-in JAXB-2 Maven utilise l'outil XJC fourni par JDK, un outil de compilation JAXB Binding qui génère des classes Java à partir de XSD (XML Schema Definition).

Créons un fichier __user.xsd__ simple et utilisons le plug-in JAXB-2 Maven pour générer des classes Java à partir de ce schéma XSD:

[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>
Configurons le plugin JAXB-2 Maven:

[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>

Par défaut, ce plugin localise les fichiers XSD dans __src/main/xsd__. Nous pouvons configurer la recherche XSD en modifiant la section de configuration de ce plugin dans le __pom.xml__ en conséquence.

Par défaut, ces classes Java sont générées dans le dossier __target/driven-resources/jaxb__. Nous pouvons changer le répertoire de sortie en ajoutant un élément __outputDirectory__ à la configuration du plugin. Nous pouvons également ajouter un élément __clearOutputDir__ avec une valeur false pour empêcher l’effacement des fichiers de ce répertoire.

Nous pouvons également configurer une liaison globale JAXB qui remplace les règles de liaison par défaut:

[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>
La __global.xjb__ ci-dessus remplace le type __dateTime__ par le type __java.util.Calendar__. + Lorsque nous construisons le projet, il génère des fichiers de classe dans le dossier __src/main/java__ et le package __com.baeldung.jaxb.gen__.

====  **  7.2. Génération de schéma XSD à partir de Java **

Le même plugin utilise l'outil fourni par JDK, __Schemagen__. Il s’agit d’un outil de compilation JAXB Binding capable de générer un schéma XSD à partir de classes Java.

Pour qu'une classe Java soit éligible pour un schéma candidat XSD, elle doit être annotée avec une annotation __ @ XmlType__.

Nous réutilisons les fichiers de classe Java de l'exemple précédent. Configurons le plugin:

[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>

Par défaut, JAXB analyse tous les dossiers sous __src/main/java__ de manière récursive pour les classes JAXB annotées. Nous pouvons spécifier un dossier __source__ différent pour nos classes annotées JAXB en ajoutant un élément __source__ à la configuration du plug-in.

Nous pouvons également enregistrer un __transformSchemas__, un post-processeur responsable de nommer le schéma XSD. Cela fonctionne en faisant correspondre le __namespace__ avec le namespace du __ @ XmlType__ de votre classe Java.

Lorsque nous générons le projet, il génère un fichier __user-gen.xsd__ dans le répertoire __src/main/resources__.

===  **  8. **  **  Conclusion **

Dans cet article, nous avons abordé les concepts d'introduction à JAXB. Pour plus de détails, consultez la page d'accueil http://www.oracle.com/technetwork/articles/javase/index-140168.htmlJJAXB]

Nous pouvons trouver le code source de cet article sur https://github.com/eugenp/tutorials/tree/master/jaxb[GitHub].