1. JAXB ilə tanışlıq
JAXB (Java Architecture for XML Binding) — Java obyektlərini XML-ə və əksinə çevirmək (binding) üçün Java-nın standart texnologiyasıdır. JAXB vasitəsilə obyektləri asanlıqla XML fayllarına seriyallaşdırmaq, sonra isə həmin fayllardan bərpa etmək olar.
JAXB, Java-nın standart kitabxanasına 11-ci versiyaya qədər daxildi. Java 11-dən etibarən JAXB ayrıca modul kimi ayrılıb; onu Maven/Gradle vasitəsilə qoşmaq və ya əl ilə yükləmək lazımdır. Müasir Java versiyaları üçün asılılıqları əlavə edin:
<!-- Maven üçün nümunə -->
<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>
Ümumiyyətlə XML nə üçün lazımdır?
- XML — sistemlər arasında məlumat mübadiləsi, konfiqurasiya və məlumatların saxlanması üçün geniş istifadə olunan universal, insan tərəfindən oxuna bilən bir formatdır.
- İkili (binary) seriyallaşdırmadan fərqli olaraq, XML-i gözlə oxumaq, sxemə görə doğrulamaq və brauzerdə açmaq asandır.
2. JAXB-nin əsas sinifləri və annotasiyaları
JAXB, seriyallaşdırma/deseriyallaşdırma prosesinə nəzarət etmək üçün siniflər və onların sahələri annotasiyalarla işarələnən bir model üzərində işləyir.
Əsas annotasiyalar
| Annotasiya | Təyinatı |
|---|---|
|
XML-in kök elementini (sinfin özünü) göstərir |
|
Sahə/xassəni XML elementi kimi işarələyir |
|
Sahə/xassəni XML atributu kimi işarələyir |
|
Elementlərin sırasını, tip adını və s. idarə edir |
|
Sahəni seriyallaşdırmadan çıxarır |
Əsas siniflər
- JAXBContext — giriş nöqtəsi, konkret siniflər üçün seriyallaşdırma/deseriyallaşdırma konteksini yaradır.
- Marshaller — obyekti XML-ə çevirir (marshalling, marshal()).
- Unmarshaller — XML-i obyektə çevirir (unmarshalling, unmarshal()).
3. Nümunə: obyektin XML-ə seriyallaşdırılması
Seriyallaşdıracağımız bir sinif yaradaq. Gəlin bu, oyunumuz üçün bir personaj olsun:
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() {} // Mütləq boş 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") — sinif kök elementə çevrilir <player>.
- @XmlElement — sahə ayrı XML elementi olacaq (<name>, <level>).
- @XmlAttribute — sahə kök elementin atributu olacaq (health="100").
- Boş konstruktoru unutmayın! JAXB onu deseriyallaşdırma üçün tələb edir.
Obyektin XML-ə seriyallaşdırılması
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); // Səliqəli çıxış
marshaller.marshal(player, System.out); // XML-i konsola yazırıq
// marshaller.marshal(player, new File("player.xml")); // Yaxud fayla
}
}
Nəticə:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<player health="100">
<name>Aragorn</name>
<level>5</level>
</player>
Obyektin XML-dən deseriyallaşdırılması
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() + ", səviyyə: " + player.getLevel() + ", sağlamlıq: " + player.getHealth());
}
}
4. JAXB-nin xüsusiyyətləri və məhdudiyyətləri
Siniflərə tələblər
- Parametrsiz public konstruktor — mütləqdir.
- Düzgün işləməsi üçün getter və setter-lərdən istifadə edin.
- Bütün seriyallaşdırılan sahələr əlçatan olmalıdır (public API vasitəsilə).
- Yuvalanmış obyektlər və kolleksiyalar da seriyallaşdırıla bilməlidir (annotasiya edin və boş konstruktor əlavə edin).
Kolleksiyalar və yuvalanmış obyektlərlə iş
Tutaq ki, oyunçunun inventarı (əşyalar siyahısı) var. Kolleksiyanı necə seriyallaşdırmaq olar?
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import java.util.List;
@XmlRootElement(name = "player")
public class Player {
// ... digər sahələr
private List<String> inventory;
public Player() {}
// ... digər getter/setter-lər
@XmlElementWrapper(name = "inventory")
@XmlElement(name = "item")
public List<String> getInventory() {
return inventory;
}
public void setInventory(List<String> inventory) {
this.inventory = inventory;
}
}
Seriyallaşdırmanın nəticəsi:
<player health="100">
<name>Aragorn</name>
<level>5</level>
<inventory>
<item>Sword</item>
<item>Shield</item>
</inventory>
</player>
- @XmlElementWrapper — kolleksiyanın ətrafında “wrapper” yaradır (element <inventory>).
- @XmlElement(name = "item") — siyahının hər elementi <item> kimi seriyallaşdırılır.
Əgər yuvalanmış obyektləriniz varsa (məsələn, Position), onları da annotasiya etmək və boş konstruktor əlavə etmək lazımdır.
5. Təcrübə: obyektin XML-ə seriyallaşdırılması və XML-dən deseriyallaşdırılması
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-lər qısalıq naminə buraxılıb
}
@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-lər buraxılıb
}
Seriyallaşdırma:
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 nəticəsi:
<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>
Deseriyallaşdırma da oxşar şəkildə işləyir: siniflər düzgün təsvir olunubsa, JAXB yuvalanmış obyektləri və kolleksiyaları özü emal edəcək.
6. Cədvəl: JAXB-nin əsas annotasiyaları və onların effekti
| Annotasiya | Harada istifadə olunur | XML-də nə edir |
|---|---|---|
|
Sinif | Kök element |
|
Getter/sahə | XML daxilində element |
|
Getter/sahə | Elementdə atribut |
|
Kolleksiya getter-i | Kolleksiya üçün “wrapper” (məsələn, <list>) |
|
Sahə/getter | Sahəni seriyallaşdırmadan çıxarır |
|
Sinif | Elementlərin sırasını, tip adını idarə edir |
7. JAXB-nin xüsusiyyətləri və məhdudiyyətləri
Elementlərin sırası
Susmaya görə JAXB elementləri əlifba sırası ilə çıxara bilər. Sıranı açıq şəkildə təyin etmək üçün @XmlType və propOrder xassəsindən istifadə edin:
@XmlType(propOrder = {"name", "level", "inventory", "position"})
Sahələrin istisna edilməsi
Hər hansı sahəni/getter-i seriyallaşdırmamaq üçün @XmlTransient istifadə edin:
@XmlTransient
public String getSecretCode() { ... }
Kolleksiyalarla problemlər
- Genericssiz “xam” kolleksiyalardan istifadə etməyin: List<Type> yazın, List yox.
- Kolleksiya obyektlər saxlayırsa, onların sinifləri də annotasiya olunmalı və boş konstruktoru olmalıdır.
Xətalar
- Boş konstruktor yoxdur — unmarshalling zamanı JAXBException alacaqsınız.
- Annotasiya olunmamış yuvalanmış sinif — JAXB onu seriyallaşdırıb/deseriyallaşdıra bilməyəcək.
- Standart olmayan tiplər (məsələn, LocalDate) adapter tələb edir (@XmlJavaTypeAdapter).
8. JAXB ilə işləyərkən tipik xətalar
Xəta №1: Boş konstruktor yoxdur. JAXB seriyallaşdırılan sinifdə parametrsiz public konstruktor olmasını tələb edir. Əgər o yoxdursa — unmarshalling zamanı JAXBException istisnası baş verəcək.
Xəta №2: Annotasiya olunmamış yuvalanmış obyektlər. Əgər sahə-obyektiniz varsa, amma onun sinfi @XmlRootElement və ya ən azı @XmlType ilə annotasiya edilməyibsə, JAXB onu düzgün seriyallaşdırıb/deseriyallaşdıra bilməyəcək.
Xəta №3: Kolleksiyalarla problemlər. JAXB element tipləri göstərilməyən “xam” kolleksiyaları başa düşmür. Generics istifadə edin və kolleksiyaları düzgün annotasiya edin (@XmlElementWrapper + @XmlElement).
Xəta №4: Elementlərin sırasına qeyri-açıq nəzarət. XML-də elementlərin sırası inteqrasiya üçün vacibdirsə, @XmlType ilə propOrder istifadə edin; əks halda JAXB elementləri başqa sırada (məsələn, əlifba ilə) verə bilər.
Xəta №5: Adapter olmadan standart olmayan tiplərin istifadəsi. JAXB bəzi tipləri (məsələn, LocalDate) adaptersiz seriyallaşdıra bilmir. @XmlJavaTypeAdapter tətbiq edin və ya dəyəri sətir kimi seriyallaşdırın.
GO TO FULL VERSION