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 |
|---|---|
|
Kennzeichnet das Wurzelelement des XML (die Klasse selbst) |
|
Kennzeichnet ein Feld/Property als XML-Element |
|
Kennzeichnet ein Feld/Property als XML-Attribut |
|
Steuert die Reihenfolge der Elemente, den Typnamen usw. |
|
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 |
|---|---|---|
|
Klasse | Wurzelelement |
|
Getter/Feld | Element innerhalb des XML |
|
Getter/Feld | Attribut eines Elements |
|
Getter der Collection | „Hülle“ der Collection (z. B. <list>) |
|
Feld/Getter | Schließt ein Feld von der Serialisierung aus |
|
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.
GO TO FULL VERSION