Java JAXB
Mapeie XML para objetos Java e vice-versa usando anotações JAXB e Marshaller/Unmarshaller em Java.
JAXB (Jakarta XML Binding, anteriormente Java Architecture for XML Binding) mapeia objetos Java para XML e vice-versa sem que você precise escrever código de análise manualmente. Você anota uma classe simples e a entrega a um Marshaller para produzir XML ou a um Unmarshaller para ler XML e convertê-lo em objetos. O JAXB existia no JDK (javax.xml.bind) até o Java 8, foi removido no Java 11 e agora é distribuído como uma dependência separada sob o namespace jakarta.xml.bind. As anotações e o modelo de marshal/unmarshal são iguais nos dois casos.
Este capítulo aborda o que é o binding JAXB, as anotações principais, como fazer marshal de um objeto para XML e unmarshal de XML de volta para objetos, como coleções são mapeadas e a mudança de namespace entre Java 8 e Java moderno. JAXB é uma API de binding: ao contrário dos parsers de nível mais baixo DOM e SAX abordados anteriormente nesta parte, você nunca toca a árvore XML — você trabalha com objetos Java comuns.
Quando usar JAXB
Use JAXB quando seus dados já possuem (ou merecem) uma classe, e XML é apenas o formato de transmissão ou armazenamento:
- Leitura e escrita de arquivos de configuração ou documentos onde a estrutura é estável e conhecida com antecedência.
- SOAP / serviços web legados, onde o contrato é um esquema XML e as ferramentas geram as classes.
- Round-tripping — carregar XML, alterar o objeto e gravá-lo de volta sem análise manual.
Prefira DOM ou SAX quando a estrutura for irregular, você precisar apenas de alguns campos de um documento grande ou não houver uma classe natural para vincular. E se você controla ambos os lados e precisa apenas de um formato de dados compacto, JSON com Jackson costuma ser mais leve que XML.
A ideia principal: anotações descrevem o mapeamento
Você não escreve código que percorre a árvore XML. Em vez disso, você descreve, com anotações em uma classe, como seus campos correspondem a elementos e atributos XML. O JAXB lê essas anotações em tempo de execução e gera a conversão para você em ambas as direções. Um POJO se torna um esquema autodocumentado.
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() {}
}As anotações principais
Um conjunto de anotações cobre quase todos os mapeamentos. Elas estão no pacote jakarta.xml.bind.annotation (ou javax.xml.bind.annotation no Java 8).
| Anotação | Efeito |
|---|---|
@XmlRootElement | Marca uma classe como raiz do documento; nomeia o elemento mais externo |
@XmlElement | Mapeia um campo/propriedade para um elemento aninhado |
@XmlAttribute | Mapeia um campo/propriedade para um atributo no seu elemento |
@XmlElementWrapper | Envolve uma coleção em um elemento contêiner |
@XmlTransient | Exclui um campo do XML completamente |
@XmlAccessorType | Controla se o JAXB vincula campos ou getters por padrão |
Marshalling: objeto para XML
Um JAXBContext é o ponto de entrada — crie um para suas classes raiz e solicite um Marshaller. O marshaller transforma um grafo de objetos em XML. Definir JAXB_FORMATTED_OUTPUT produz saída legível e indentada.
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 para objeto
O processo inverso é simétrico: solicite ao mesmo JAXBContext um Unmarshaller e aponte-o para uma fonte — um File, InputStream, Reader ou StringReader. O JAXB constrói o objeto usando o construtor sem argumentos e o preenche com os elementos e atributos.
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()); // 2018O JAXB não está no classpath deste executor de código (é uma dependência externa no Java moderno), portanto o exemplo abaixo demonstra o mesmo round trip de marshal/unmarshal usando apenas a API DOM integrada do JDK. O conceito é idêntico: um atributo na raiz, elementos filhos para os campos e um round trip de volta a um objeto igual.
O que observar na execução:
- O XML serializado coloca
yearcomo um atributo em<book>, mastitleeauthorcomo elementos filhos — exatamente a divisão que@XmlAttributeversus@XmlElementcontrola no JAXB real. A escolha da anotação é o que decide elemento-vs-atributo. - A tag raiz é
book, relatada porel.getTagName(). No JAXB esse nome vem de@XmlRootElement(name = "book"); aqui é a string passada paracreateElement. De qualquer forma, o elemento mais externo identifica o tipo do documento. - Marshalling e unmarshalling são operações espelhadas sobre a mesma estrutura: o programa constrói XML a partir de um
Booke depois reconstrói umBooka partir desse XML. OMarshallere oUnmarshallerdo JAXB são exatamente esse par, apoiados por um únicoJAXBContext. round-trip equal : trueprova que os dados sobreviveram à viagem intactos — título, autor e ano retornaram corretamente. Um binding correto é sem perdas, que é a propriedade em que você conta quando XML é seu formato de transmissão.- Ler
yearde volta exigiuInteger.parseIntporque XML é todo texto. O JAXB oculta isso convertendo o texto de atributos e elementos para o tipo Java declarado (int,LocalDate,BigDecimal) automaticamente; sem ele, cada campo é uma string que você precisa analisar manualmente.
Mapeamento de coleções
Um List mapeia para elementos repetidos. Por padrão, cada item é nomeado conforme o campo, o que pode produzir um documento plano e difícil de ler. @XmlElementWrapper adiciona um elemento contêiner para que os itens fiquem agrupados — o padrão comum e legível.
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() {}
}Com o wrapper, a saída fica aninhada de forma limpa:
<library>
<books>
<book year="2018"><title>Effective Java</title>...</book>
<book year="2008"><title>Clean Code</title>...</book>
</books>
</library>Remova @XmlElementWrapper e os elementos <book> ficarão diretamente sob <library> sem nenhum elemento de agrupamento — válido, mas mais plano. Escolher entre os dois é a decisão de mapeamento de coleção mais comum no JAXB.
Java 8 vs. Java moderno: a mudança de namespace
O maior problema é a renomeação do pacote. No Java 8 a API está incluída e vive sob javax.xml.bind. A partir do Java 11 ela não está mais incluída e vive sob jakarta.xml.bind, sendo adicionada como dependência.
| Java 8 | Java 11+ | |
|---|---|---|
| Pacote | javax.xml.bind | jakarta.xml.bind |
| No classpath? | Integrado | Adicionar dependência |
| Artefato em tempo de execução | JDK | org.glassfish.jaxb:jaxb-runtime |
Para um build Maven no Java moderno, você adiciona a API mais uma implementação em tempo de execução:
<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>Prática
Veja também
- Trabalhando com XML em Java — visão geral das APIs XML e quando cada uma se aplica.
- Parser DOM e parser SAX — as alternativas de nível mais baixo ao binding.
- Jackson — a mesma ideia de anotar e vincular aplicada ao JSON.