W3docs

Java JAXB

Mappez du XML vers des objets Java et inversement avec les annotations JAXB et les classes Marshaller/Unmarshaller.

JAXB (Jakarta XML Binding, anciennement Java Architecture for XML Binding) fait correspondre des objets Java à du XML et vice versa, sans que vous ayez à écrire du code d'analyse à la main. Vous annotez une classe ordinaire, puis vous la confiez à un Marshaller pour produire du XML, ou à un Unmarshaller pour lire du XML vers des objets. JAXB était intégré au JDK (javax.xml.bind) jusqu'à Java 8, a été supprimé à partir de Java 11, et est désormais distribué comme dépendance séparée sous le namespace jakarta.xml.bind. Les annotations et le modèle marshal/unmarshal sont identiques dans les deux versions.

Ce chapitre explique ce qu'est la liaison JAXB, les annotations principales, comment marshaller un objet en XML et unmarshaller du XML en retour, comment les collections sont mappées, et le changement de namespace entre Java 8 et les versions modernes de Java. JAXB est une API de liaison : contrairement aux parseurs bas niveau DOM et SAX abordés précédemment dans cette partie, vous ne manipulez jamais l'arbre XML — vous travaillez avec des objets Java ordinaires.

Quand utiliser JAXB

Utilisez JAXB lorsque vos données possèdent déjà (ou méritent) une classe, et que XML n'est que le format de transfert ou de stockage :

  • Lecture et écriture de fichiers de configuration ou de documents dont la structure est stable et connue à l'avance.
  • Services web SOAP / legacy, où le contrat est un schéma XML et des outils génèrent les classes.
  • Aller-retour (round-tripping) — charger du XML, modifier l'objet, et le réécrire sans analyse manuelle.

Préférez DOM ou SAX lorsque la structure est irrégulière, que vous n'avez besoin que de quelques champs d'un grand document, ou qu'il n'existe pas de classe naturelle à lier. Et si vous contrôlez les deux extrémités et avez simplement besoin d'un format de données compact, JSON avec Jackson est généralement plus léger que XML.

L'idée centrale : les annotations décrivent le mapping

Vous n'écrivez pas de code qui parcourt l'arbre XML. À la place, vous décrivez, via des annotations sur une classe, comment ses champs correspondent aux éléments et attributs XML. JAXB lit ces annotations au moment de l'exécution et génère la conversion pour vous dans les deux sens. Un POJO devient ainsi un schéma auto-documenté.

import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlAttribute;

@XmlRootElement(name = "book")
public class Book {
    private String title;
    private String author;
    private int year;

    @XmlElement public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }

    @XmlElement public String getAuthor() { return author; }
    public void setAuthor(String author) { this.author = author; }

    @XmlAttribute public int getYear() { return year; }
    public void setYear(int year) { this.year = year; }

    // JAXB requires a public no-arg constructor for unmarshalling
    public Book() {}
}

Les annotations principales

Une poignée d'annotations couvre presque tous les mappings. Elles se trouvent dans le package jakarta.xml.bind.annotation (ou javax.xml.bind.annotation sur Java 8).

AnnotationEffet
@XmlRootElementMarque une classe comme racine de document ; nomme l'élément le plus externe
@XmlElementMappe un champ/propriété vers un élément imbriqué
@XmlAttributeMappe un champ/propriété vers un attribut de son élément
@XmlElementWrapperEncapsule une collection dans un élément conteneur
@XmlTransientExclut un champ du XML entièrement
@XmlAccessorTypeContrôle si JAXB lie les champs ou les getters par défaut

Marshalling : objet vers XML

Un JAXBContext est le point d'entrée — créez-en un pour vos classes racines, puis demandez-lui un Marshaller. Le marshaller transforme un graphe d'objets en XML. Définir JAXB_FORMATTED_OUTPUT produit une sortie lisible et indentée.

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Marshaller;

Book book = new Book();
book.setTitle("Effective Java");
book.setAuthor("Joshua Bloch");
book.setYear(2018);

JAXBContext context = JAXBContext.newInstance(Book.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(book, System.out);
// <book year="2018"><title>Effective Java</title><author>Joshua Bloch</author></book>

Unmarshalling : XML vers objet

L'opération inverse est symétrique : demandez au même JAXBContext un Unmarshaller et pointez-le vers une source — un File, un InputStream, un Reader ou un StringReader. JAXB construit l'objet à l'aide du constructeur sans argument et le remplit à partir des éléments et attributs.

import jakarta.xml.bind.Unmarshaller;
import java.io.StringReader;

String xml = "<book year=\"2018\">"
           + "<title>Effective Java</title>"
           + "<author>Joshua Bloch</author></book>";

Unmarshaller unmarshaller = context.createUnmarshaller();
Book book = (Book) unmarshaller.unmarshal(new StringReader(xml));
System.out.println(book.getTitle()); // Effective Java
System.out.println(book.getYear());  // 2018

JAXB ne figure pas dans le classpath de cet environnement d'exécution (c'est une dépendance externe sur Java moderne), donc l'exemple ci-dessous illustre le même aller-retour marshal/unmarshal en utilisant uniquement l'API DOM intégrée au JDK. Le concept est identique : un attribut sur la racine, des éléments enfants pour les champs, et un retour vers un objet égal.

java— editable, runs on the server

Ce qu'il faut retenir de l'exécution :

  • Le XML marshallé place year comme attribut sur <book>, mais title et author comme éléments enfants — exactement le découpage que @XmlAttribute versus @XmlElement contrôle dans un vrai JAXB. Le choix de l'annotation détermine élément ou attribut.
  • La balise racine est book, rapportée par el.getTagName(). En JAXB, ce nom provient de @XmlRootElement(name = "book") ; ici c'est la chaîne passée à createElement. Dans les deux cas, l'élément le plus externe identifie le type du document.
  • Le marshalling et l'unmarshalling sont des opérations miroir sur la même structure : le programme construit du XML depuis un Book, puis reconstruit un Book depuis ce XML. Le Marshaller et l'Unmarshaller de JAXB sont exactement cette paire, supportée par un JAXBContext.
  • round-trip equal : true prouve que les données ont survécu au trajet — title, author et year sont tous revenus intacts. Une liaison correcte est sans perte, ce qui est la propriété sur laquelle vous comptez lorsque XML est votre format de transmission.
  • La relecture de year a nécessité Integer.parseInt car XML est entièrement du texte. JAXB masque cela en convertissant le texte des attributs et éléments vers le type Java déclaré (int, LocalDate, BigDecimal) automatiquement ; sans cela, chaque champ est une chaîne que vous devez analyser vous-même.

Mapping des collections

Une List se mappe à des éléments répétés. Par défaut, chaque élément porte le nom du champ, ce qui peut produire un document plat et difficile à lire. @XmlElementWrapper ajoute un élément conteneur pour que les éléments soient regroupés — le pattern courant et lisible.

import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import java.util.List;

@XmlRootElement(name = "library")
public class Library {
    private List<Book> books;

    @XmlElementWrapper(name = "books") // outer <books> element
    @XmlElement(name = "book")         // each item is a <book>
    public List<Book> getBooks() { return books; }
    public void setBooks(List<Book> books) { this.books = books; }

    public Library() {}
}

Avec le wrapper, la sortie est bien imbriquée :

<library>
  <books>
    <book year="2018"><title>Effective Java</title>...</book>
    <book year="2008"><title>Clean Code</title>...</book>
  </books>
</library>

Supprimez @XmlElementWrapper et les éléments <book> se retrouvent directement sous <library> sans élément de regroupement — valide, mais plus plat. Choisir entre les deux est la décision de mapping de collection la plus courante en JAXB.

Java 8 vs. Java moderne : le déplacement de namespace

Le principal écueil est le renommage de package. Sur Java 8, l'API est intégrée et se trouve sous javax.xml.bind. À partir de Java 11, elle est désintégrée et se trouve sous jakarta.xml.bind, et doit être ajoutée en tant que dépendance.

Java 8Java 11+
Packagejavax.xml.bindjakarta.xml.bind
Dans le classpath ?IntégréAjouter une dépendance
Artefact d'exécutionJDKorg.glassfish.jaxb:jaxb-runtime

Pour un build Maven sur Java moderne, vous ajoutez l'API ainsi qu'une implémentation d'exécution :

<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.2</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>4.0.5</version>
</dependency>

Pratique

Pratique
En JAXB, quelle est la différence entre annoter une propriété avec @XmlElement et @XmlAttribute ?
En JAXB, quelle est la différence entre annoter une propriété avec @XmlElement et @XmlAttribute ?

Voir aussi

Was this page helpful?