CodeGym /Kurse /JAVA 25 SELF /Arbeiten mit XML über JAXB: Grundlagen, Annotationen

Arbeiten mit XML über JAXB: Grundlagen, Annotationen

JAVA 25 SELF
Level 47, Lektion 3
Verfügbar

1. Einführung in JAXB

JAXB (Java Architecture for XML Binding) – ist die Standardtechnologie von Java zur Umwandlung (Binding) von Java-Objekten in XML und zurück. Mit JAXB lassen sich Objekte einfach in XML-Dateien serialisieren und anschließend aus diesen Dateien wiederherstellen.

JAXB war bis einschließlich Version 11 Teil der Java-Standardbibliothek. Ab Java 11 wurde JAXB in ein separates Modul ausgelagert, das über Maven/Gradle eingebunden oder manuell heruntergeladen werden muss. Für aktuelle Java-Versionen fügen Sie die folgenden Abhängigkeiten hinzu:

<!-- Beispiel für 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>

Wozu braucht man überhaupt XML?

  • XML ist ein universelles, menschenlesbares Format, das weit verbreitet für den Datenaustausch zwischen Systemen, für Konfigurationen und zur Speicherung von Informationen verwendet wird.
  • Im Unterschied zur binären Serialisierung lässt sich XML leicht mit bloßem Auge lesen, per Schema validieren und im Browser öffnen.

2. Zentrale Klassen und Annotationen von JAXB

JAXB arbeitet auf Basis von Annotationen, mit denen Klassen und deren Felder markiert werden, um den Serialisierungs-/Deserialisierungsprozess zu steuern.

Wichtigste Annotationen

Annotation Wofür
@XmlRootElement
Kennzeichnet das Wurzelelement des XML (die Klasse selbst)
@XmlElement
Kennzeichnet ein Feld/Property als XML-Element
@XmlAttribute
Kennzeichnet ein Feld/Property als XML-Attribut
@XmlType
Steuert die Reihenfolge der Elemente, den Typnamen usw.
@XmlTransient
Schließt ein Feld von der Serialisierung aus

Wichtigste Klassen

  • JAXBContext – Einstiegspunkt; erzeugt den Kontext für die Serialisierung/Deserialisierung konkreter Klassen.
  • Marshaller – wandelt ein Objekt in XML um (Marshalling, marshal()).
  • Unmarshaller – wandelt XML in ein Objekt um (Unmarshalling, unmarshal()).

3. Beispiel: Serialisierung eines Objekts nach XML

Wir erstellen eine Klasse, die wir serialisieren möchten. Nehmen wir an, es handelt sich um eine Spielfigur für unser Spiel:

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() {} // Erforderlicher parameterloser Konstruktor!

    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") – die Klasse wird zum Wurzelelement <player>.
  • @XmlElement – das Feld wird ein eigenes XML-Element (<name>, <level>).
  • @XmlAttribute – das Feld wird ein Attribut des Wurzelelements (health="100").
  • Vergessen Sie den parameterlosen Konstruktor nicht! JAXB benötigt ihn für die Deserialisierung.

Serialisierung eines Objekts nach 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); // Schön formatierte Ausgabe

        marshaller.marshal(player, System.out); // XML in die Konsole schreiben
        // marshaller.marshal(player, new File("player.xml")); // Oder in eine Datei
    }
}

Ergebnis:

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

Deserialisierung eines Objekts aus 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() + ", Level: " + player.getLevel() + ", Gesundheit: " + player.getHealth());
    }
}

4. Besonderheiten und Einschränkungen von JAXB

Anforderungen an Klassen

  • Öffentlicher, parameterloser Konstruktor – verpflichtend.
  • Für korrektes Arbeiten verwenden Sie Getter und Setter.
  • Alle zu serialisierenden Felder müssen zugänglich sein (über die öffentliche API).
  • Verschachtelte Objekte und Collections müssen ebenfalls serialisierbar sein (annotieren und einen parameterlosen Konstruktor bereitstellen).

Arbeiten mit Collections und verschachtelten Objekten

Angenommen, der Spieler hat ein Inventar (eine Liste von Items). Wie serialisiert man eine Collection?

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

@XmlRootElement(name = "player")
public class Player {
    // ... übrige Felder

    private List<String> inventory;

    public Player() {}

    // ... übrige Getter/Setter

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

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

Serialisierungsergebnis:

<player health="100">
    <name>Aragorn</name>
    <level>5</level>
    <inventory>
        <item>Sword</item>
        <item>Shield</item>
    </inventory>
</player>
  • @XmlElementWrapper – erzeugt eine „Hülle“ um die Collection (Element <inventory>).
  • @XmlElement(name = "item") – jedes Listenelement wird als <item> serialisiert.

Wenn Sie verschachtelte Objekte haben (z. B. Position

5. Praxis: Serialisierung und Deserialisierung eines Objekts nach 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; }

    // Setter der Kürze halber weggelassen
}

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

    // Setter weggelassen
}

Serialisierung:

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

XML-Ergebnis:

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

Die Deserialisierung funktioniert analog: JAXB verarbeitet verschachtelte Objekte und Collections automatisch, sofern die Klassen korrekt beschrieben sind.

6. Tabelle: wichtigste JAXB-Annotationen und ihre Wirkung

Annotation Einsatzort Wirkung im XML
@XmlRootElement
Klasse Wurzelelement
@XmlElement
Getter/Feld Element innerhalb des XML
@XmlAttribute
Getter/Feld Attribut eines Elements
@XmlElementWrapper
Getter der Collection „Hülle“ der Collection (z. B. <list>)
@XmlTransient
Feld/Getter Schließt ein Feld von der Serialisierung aus
@XmlType
Klasse Steuert die Reihenfolge der Elemente und den Typnamen

7. Besonderheiten und Einschränkungen von JAXB

Reihenfolge der Elemente

Standardmäßig kann JAXB Elemente in alphabetischer Reihenfolge ausgeben. Um die Reihenfolge explizit festzulegen, verwenden Sie @XmlType und die Eigenschaft propOrder:

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

Felder ausschließen

Um ein Feld/Getter nicht zu serialisieren, verwenden Sie @XmlTransient:

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

Probleme mit Collections

  • Verwenden Sie keine „rohen“ Collections ohne Generics: Schreiben Sie List<Type> statt List.
  • Wenn eine Collection Objekte enthält, müssen deren Klassen ebenfalls annotiert sein und einen parameterlosen Konstruktor haben.

Fehler

  • Fehlender parameterloser Konstruktor – führt beim Unmarshalling zu einer JAXBException.
  • Nicht annotierte verschachtelte Klasse – JAXB kann sie nicht serialisieren/deserialisieren.
  • Nicht standardmäßige Typen (z. B. LocalDate) erfordern einen Adapter (@XmlJavaTypeAdapter).

8. Typische Fehler bei der Arbeit mit JAXB

Fehler Nr. 1: Es fehlt ein parameterloser Konstruktor. JAXB verlangt, dass die zu serialisierende Klasse einen öffentlichen, parameterlosen Konstruktor besitzt. Fehlt er, tritt beim Unmarshalling eine JAXBException auf.

Fehler Nr. 2: Nicht annotierte verschachtelte Objekte. Wenn Sie ein Objektfeld haben, dessen Klasse jedoch nicht mit @XmlRootElement oder zumindest @XmlType annotiert ist, kann JAXB es nicht korrekt serialisieren/deserialisieren.

Fehler Nr. 3: Probleme mit Collections. JAXB versteht keine „rohen“ Collections ohne Angabe des Elementtyps. Verwenden Sie Generics und annotieren Sie Collections korrekt (@XmlElementWrapper + @XmlElement).

Fehler Nr. 4: Implizite Steuerung der Elementreihenfolge. Wenn die Reihenfolge der Elemente im XML für die Integration wichtig ist, verwenden Sie @XmlType mit propOrder; andernfalls kann JAXB Elemente in einer anderen Reihenfolge (z. B. alphabetisch) ausgeben.

Fehler Nr. 5: Verwendung von nicht standardmäßigen Typen ohne Adapter. JAXB kann einige Typen (z. B. LocalDate) ohne Adapter nicht serialisieren. Verwenden Sie @XmlJavaTypeAdapter oder serialisieren Sie den Wert als String.

1
Aufgabe
JAVA 25 SELF, Level 47, Lektion 3
Gesperrt
Entwurf eines Bucheintrags für die digitale Bibliothek 📖
Entwurf eines Bucheintrags für die digitale Bibliothek 📖
1
Aufgabe
JAVA 25 SELF, Level 47, Lektion 3
Gesperrt
Laden eines Buches aus XML in die Anwendung 📥
Laden eines Buches aus XML in die Anwendung 📥
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION