W3docs

Java JAXB

Mappa XML su oggetti Java e viceversa con annotazioni JAXB e Marshaller/Unmarshaller.

JAXB (Jakarta XML Binding, precedentemente Java Architecture for XML Binding) mappa gli oggetti Java su XML e viceversa senza dover scrivere codice di parsing a mano. Annoti una classe normale, poi la passi a un Marshaller per produrre XML o a un Unmarshaller per leggere XML in oggetti. JAXB era incluso nel JDK (javax.xml.bind) fino a Java 8, è stato rimosso in Java 11 e ora viene distribuito come dipendenza separata nel namespace jakarta.xml.bind. Le annotazioni e il modello marshal/unmarshal sono gli stessi in entrambi.

Questo capitolo tratta cos'è il binding JAXB, le annotazioni principali, come marshallizzare un oggetto in XML e de-marshallizzare XML in oggetti, come vengono mappate le collezioni e la differenza di namespace tra Java 8 e le versioni moderne. JAXB è un'API di binding: a differenza dei parser di basso livello DOM e SAX trattati in precedenza in questa parte, non tocchi mai l'albero XML — lavori con normali oggetti Java.

Quando usare JAXB

Usa JAXB quando i tuoi dati hanno già (o meritano) una classe e XML è solo il formato di trasporto o storage:

  • Lettura e scrittura di file di configurazione o documenti dove la struttura è stabile e nota in anticipo.
  • Servizi web SOAP / legacy, dove il contratto è uno schema XML e gli strumenti generano le classi.
  • Round-trip — caricare XML, modificare l'oggetto e riscriverlo senza parsing manuale.

Usa invece DOM o SAX quando la struttura è irregolare, hai bisogno solo di pochi campi da un documento di grandi dimensioni, o non esiste una classe naturale a cui fare binding. E se controlli entrambe le estremità e hai solo bisogno di un formato dati compatto, JSON con Jackson è di solito più leggero di XML.

L'idea fondamentale: le annotazioni descrivono il mapping

Non scrivi codice che percorre l'albero XML. Invece descrivi, con annotazioni su una classe, come i suoi campi corrispondono agli elementi e agli attributi XML. JAXB legge quelle annotazioni a runtime e genera la conversione per te in entrambe le direzioni. Un POJO diventa uno schema auto-documentante.

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() {}
}

Le annotazioni principali

Un insieme di annotazioni copre quasi ogni tipo di mapping. Si trovano nel package jakarta.xml.bind.annotation (o javax.xml.bind.annotation su Java 8).

AnnotazioneEffetto
@XmlRootElementContrassegna una classe come radice del documento; nomina l'elemento più esterno
@XmlElementMappa un campo/proprietà a un elemento annidato
@XmlAttributeMappa un campo/proprietà a un attributo sull'elemento
@XmlElementWrapperRacchiude una collezione in un elemento contenitore
@XmlTransientEsclude un campo dall'XML completamente
@XmlAccessorTypeControlla se JAXB fa binding dei campi o dei getter per default

Marshalling: da oggetto a XML

Un JAXBContext è il punto di ingresso — creane uno per le tue classi radice, poi chiedile un Marshaller. Il marshaller trasforma un grafo di oggetti in XML. Impostare JAXB_FORMATTED_OUTPUT produce un output leggibile e indentato.

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: da XML a oggetto

L'operazione inversa è simmetrica: chiedi allo stesso JAXBContext un Unmarshaller e puntalo su una sorgente — un File, InputStream, Reader, o StringReader. JAXB costruisce l'oggetto usando il costruttore senza argomenti e lo popola dagli elementi e attributi.

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 non è nel classpath di questo code runner (è una dipendenza esterna su Java moderno), quindi l'esempio pratico seguente dimostra lo stesso round trip marshal/unmarshal usando solo l'API DOM integrata nel JDK. Il concetto è identico: un attributo sull'elemento radice, elementi figli per i campi e un round trip che restituisce un oggetto uguale.

java— editable, runs on the server

Cosa osservare dall'esecuzione:

  • L'XML marshallizzato mette year come attributo su <book> ma title e author come elementi figli — esattamente la distinzione che @XmlAttribute rispetto a @XmlElement controlla nel vero JAXB. La scelta dell'annotazione determina elemento-vs-attributo.
  • Il tag radice è book, riportato da el.getTagName(). In JAXB quel nome viene da @XmlRootElement(name = "book"); qui è la stringa passata a createElement. In entrambi i casi, l'elemento più esterno identifica il tipo del documento.
  • Il marshalling e l'unmarshalling sono operazioni speculari sulla stessa struttura: il programma costruisce XML da un Book, poi ricostruisce un Book da quell'XML. Il Marshaller e l'Unmarshaller di JAXB sono esattamente questa coppia supportata da un unico JAXBContext.
  • round-trip equal : true dimostra che i dati hanno superato il percorso intatti — title, author e year sono tutti tornati. Un binding corretto è privo di perdita, che è la proprietà su cui fai affidamento quando XML è il tuo formato wire.
  • Leggere year indietro ha richiesto Integer.parseInt perché XML è tutto testo. JAXB nasconde questo convertendo automaticamente il testo di attributi ed elementi nel tipo Java dichiarato (int, LocalDate, BigDecimal); senza di esso, ogni campo è una stringa che devi analizzare tu stesso.

Mappare le collezioni

Una List si mappa a elementi ripetuti. Per default ogni elemento viene nominato secondo il campo, il che può produrre un documento piatto e difficile da leggere. @XmlElementWrapper aggiunge un elemento contenitore in modo che gli elementi siano raggruppati — il pattern comune e leggibile.

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() {}
}

Con il wrapper, l'output si annida in modo ordinato:

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

Rimuovi @XmlElementWrapper e gli elementi <book> si trovano direttamente sotto <library> senza elemento di raggruppamento — valido, ma più piatto. Scegliere tra i due è la decisione di mapping delle collezioni più comune in JAXB.

Java 8 vs. Java moderno: il cambio di namespace

Il problema più grande è il cambio di nome del package. Su Java 8 l'API è inclusa e si trova sotto javax.xml.bind. Da Java 11 in poi è separata e si trova sotto jakarta.xml.bind, aggiunta come dipendenza.

Java 8Java 11+
Packagejavax.xml.bindjakarta.xml.bind
Nel classpath?IntegratoAggiungi una dipendenza
Artifact runtimeJDKorg.glassfish.jaxb:jaxb-runtime

Per una build Maven su Java moderno, aggiungi l'API più un'implementazione runtime:

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

Pratica

Pratica
In JAXB, qual è la differenza tra annotare una proprietà con @XmlElement e @XmlAttribute?
In JAXB, qual è la differenza tra annotare una proprietà con @XmlElement e @XmlAttribute?

Vedi anche

Was this page helpful?