CodeGym /Cursos /JAVA 25 SELF /Trabalhando com XML via JAXB: fundamentos, anotações

Trabalhando com XML via JAXB: fundamentos, anotações

JAVA 25 SELF
Nível 47 , Lição 3
Disponível

1. Introdução ao JAXB

JAXB (Java Architecture for XML Binding) — é uma tecnologia padrão do Java para converter (binding) objetos Java em XML e vice-versa. Com o JAXB, é fácil serializar objetos em arquivos XML e depois recriá-los a partir desses arquivos.

JAXB fazia parte da biblioteca padrão do Java até a versão 11 inclusive. A partir do Java 11, o JAXB foi movido para um módulo separado, que precisa ser adicionado via Maven/Gradle ou baixado manualmente. Para versões modernas do Java, adicione as dependências:

<!-- Exemplo para Maven -->
<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.0</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>4.0.3</version>
</dependency>

Por que usar XML?

  • XML é um formato universal e legível por humanos, amplamente utilizado para troca de dados entre sistemas, configuração e armazenamento de informações.
  • Ao contrário da serialização binária, o XML é fácil de ler, pode ser validado contra um esquema e aberto no navegador.

2. Principais classes e anotações do JAXB

O JAXB funciona com base em anotações, que marcam classes e seus campos para controlar o processo de serialização/desserialização.

Anotações principais

Anotação Para que serve
@XmlRootElement
Marca o elemento raiz do XML (a própria classe)
@XmlElement
Marca o campo/propriedade como um elemento XML
@XmlAttribute
Marca o campo/propriedade como um atributo XML
@XmlType
Controla a ordem dos elementos, o nome do tipo etc.
@XmlTransient
Exclui o campo da serialização

Classes principais

  • JAXBContext — ponto de entrada; cria um contexto para serializar/desserializar classes específicas.
  • Marshaller — transforma um objeto em XML (marshalling, marshal()).
  • Unmarshaller — transforma XML em objeto (unmarshalling, unmarshal()).

3. Exemplo: serialização de um objeto em XML

Vamos criar uma classe que será serializada. Que seja um personagem para o nosso jogo:

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

@XmlRootElement(name = "player")
public class Player {
    private String name;
    private int level;
    private int health;

    public Player() {} // Construtor vazio obrigatório!

    public Player(String name, int level, int health) {
        this.name = name;
        this.level = level;
        this.health = health;
    }

    @XmlElement
    public String getName() {
        return name;
    }

    public void setName(String name) { this.name = name; }

    @XmlElement
    public int getLevel() {
        return level;
    }

    public void setLevel(int level) { this.level = level; }

    @XmlAttribute
    public int getHealth() {
        return health;
    }

    public void setHealth(int health) { this.health = health; }
}
  • @XmlRootElement(name = "player") — a classe vira o elemento raiz <player>.
  • @XmlElement — o campo será um elemento XML separado (<name>, <level>).
  • @XmlAttribute — o campo será um atributo do elemento raiz (health="100").
  • Não se esqueça do construtor vazio! O JAXB o exige para a desserialização.

Serializando um objeto em XML

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

public class Main {
    public static void main(String[] args) throws Exception {
        Player player = new Player("Aragorn", 5, 100);

        JAXBContext context = JAXBContext.newInstance(Player.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // Saída formatada

        marshaller.marshal(player, System.out); // Escrevemos o XML no console
        // marshaller.marshal(player, new File("player.xml")); // Ou em arquivo
    }
}

Resultado:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<player health="100">
    <name>Aragorn</name>
    <level>5</level>
</player>

Desserializando um objeto a partir de XML

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Unmarshaller;
import java.io.File;

public class Main {
    public static void main(String[] args) throws Exception {
        JAXBContext context = JAXBContext.newInstance(Player.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();

        Player player = (Player) unmarshaller.unmarshal(new File("player.xml"));
        System.out.println(player.getName() + ", nível: " + player.getLevel() + ", vida: " + player.getHealth());
    }
}

4. Características e limitações do JAXB

Requisitos para as classes

  • Construtor público sem parâmetros — obrigatório.
  • Para funcionar corretamente, use getters e setters.
  • Todos os campos serializáveis devem ser acessíveis (via API pública).
  • Objetos aninhados e coleções também devem ser serializáveis (anote-os e adicione um construtor vazio).

Trabalhando com coleções e objetos aninhados

Suponha que o jogador tenha um inventário (lista de itens). Como serializar uma coleção?

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

@XmlRootElement(name = "player")
public class Player {
    // ... demais campos

    private List<String> inventory;

    public Player() {}

    // ... demais getters/setters

    @XmlElementWrapper(name = "inventory")
    @XmlElement(name = "item")
    public List<String> getInventory() {
        return inventory;
    }

    public void setInventory(List<String> inventory) {
        this.inventory = inventory;
    }
}

Resultado da serialização:

<player health="100">
    <name>Aragorn</name>
    <level>5</level>
    <inventory>
        <item>Sword</item>
        <item>Shield</item>
    </inventory>
</player>
  • @XmlElementWrapper — cria um “invólucro” em volta da coleção (o elemento <inventory>).
  • @XmlElement(name = "item") — cada elemento da lista é serializado como <item>.

Se você tiver objetos aninhados (por exemplo, Position), também precisa anotá-los e adicionar um construtor vazio.

5. Prática: serialização e desserialização de um objeto em XML

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

@XmlRootElement(name = "player")
public class Player {
    private String name;
    private int level;
    private int health;
    private List<String> inventory;
    private Position position;

    public Player() {}

    public Player(String name, int level, int health, List<String> inventory, Position position) {
        this.name = name;
        this.level = level;
        this.health = health;
        this.inventory = inventory;
        this.position = position;
    }

    @XmlElement
    public String getName() { return name; }

    @XmlElement
    public int getLevel() { return level; }

    @XmlAttribute
    public int getHealth() { return health; }

    @XmlElementWrapper(name = "inventory")
    @XmlElement(name = "item")
    public List<String> getInventory() { return inventory; }

    @XmlElement
    public Position getPosition() { return position; }

    // setters omitidos por brevidade
}

@XmlRootElement(name = "position")
class Position {
    private int x;
    private int y;

    public Position() {}

    public Position(int x, int y) { this.x = x; this.y = y; }

    @XmlAttribute
    public int getX() { return x; }

    @XmlAttribute
    public int getY() { return y; }

    // setters omitidos
}

Serialização:

Player player = new Player(
    "Aragorn",
    5,
    100,
    List.of("Sword", "Shield", "Potion"),
    new Position(10, 20)
);

JAXBContext context = JAXBContext.newInstance(Player.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(player, System.out);

Resultado em XML:

<player health="100">
    <name>Aragorn</name>
    <level>5</level>
    <inventory>
        <item>Sword</item>
        <item>Shield</item>
        <item>Potion</item>
    </inventory>
    <position x="10" y="20"/>
</player>

A desserialização funciona de forma análoga: o JAXB processará objetos aninhados e coleções automaticamente, se as classes estiverem descritas corretamente.

6. Tabela: principais anotações do JAXB e seu efeito

Anotação Onde usar O que faz no XML
@XmlRootElement
Classe Elemento raiz
@XmlElement
Getter/campo Elemento dentro do XML
@XmlAttribute
Getter/campo Atributo do elemento
@XmlElementWrapper
Getter da coleção “Invólucro” da coleção (por exemplo, <list>)
@XmlTransient
Campo/getter Exclui o campo da serialização
@XmlType
Classe Controla a ordem dos elementos e o nome do tipo

7. Características e limitações do JAXB

Ordem dos elementos

Por padrão, o JAXB pode emitir elementos em ordem alfabética. Para definir explicitamente a ordem, use @XmlType e a propriedade propOrder:

@XmlType(propOrder = {"name", "level", "inventory", "position"})

Exclusão de campos

Para não serializar um campo/getter, use @XmlTransient:

@XmlTransient
public String getSecretCode() { ... }

Problemas com coleções

  • Não use coleções “raw” sem generics: escreva List<Type>, e não List.
  • Se a coleção armazena objetos, as classes deles também devem ser anotadas e ter um construtor vazio.

Erros

  • Falta de construtor vazio — você receberá JAXBException ao fazer unmarshal.
  • Classe aninhada sem anotações — o JAXB não conseguirá serializá-la/desserializá-la.
  • Tipos não padrão (por exemplo, LocalDate) exigem um adaptador (@XmlJavaTypeAdapter).

8. Erros comuns ao trabalhar com JAXB

Erro nº 1: falta de construtor vazio. O JAXB exige que a classe serializável tenha um construtor público sem parâmetros. Se não houver, durante o unmarshal ocorrerá a exceção JAXBException.

Erro nº 2: objetos aninhados sem anotações. Se você tiver um campo-objeto cujo tipo não esteja anotado com @XmlRootElement ou ao menos @XmlType, o JAXB não conseguirá serializá-lo/desserializá-lo corretamente.

Erro nº 3: problemas com coleções. O JAXB não entende coleções “raw” sem indicação do tipo de elementos. Use generics e anote corretamente as coleções (@XmlElementWrapper + @XmlElement).

Erro nº 4: ordem dos elementos não controlada explicitamente. Se a ordem dos elementos no XML for importante para a integração, use @XmlType com propOrder; caso contrário, o JAXB pode emitir os elementos em outra ordem (por exemplo, alfabética).

Erro nº 5: uso de tipos não padrão sem adaptador. O JAXB não sabe serializar alguns tipos (por exemplo, LocalDate) sem um adaptador. Use @XmlJavaTypeAdapter ou serialize o valor como string.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION