V jednom z předchozích příspěvků jsem se věnoval základní práci s JAXB, kde jsem používal pouze dvě anotace a to @XmlRootElement a @XmlType. Podívejme se na část vytvořeného xml souboru.
<company>
<centers>
<code>METPRG</code>
<description>Office center Metronom in Prague</description>
<rooms>
<code>A02</code>
<numberOfSeats>14</numberOfSeats>
</rooms>
<rooms>
<code>A13</code>
<numberOfSeats>42</numberOfSeats>
</rooms>
<rooms>
<code>B08</code>
<numberOfSeats>22</numberOfSeats>
</rooms>
</centers>
<centers>
<code>AVIPRG</code>
<description>Office center Aviatica in Prague</description>
<rooms>
<code>AA41</code>
<numberOfSeats>70</numberOfSeats>
</rooms>
<rooms>
<code>CA12</code>
<numberOfSeats>38</numberOfSeats>
</rooms>
...
Company obsahuje seznam elementů center a ty v sobě mají seznam elementů room. Když se podíváte pečlivěji, uvidíte, že každý element center se jmenuje centers a každý element room se jmenuje rooms. Určitě by to lépe vypadalo, kdyby se tyto elementy jmenovaly center a room. Nebo možná ještě lépe, kdyby se element center jmenoval jednoznačněji business_center. Jak center tak room obsahují element code. Bylo čitelnější, kdyby se jmenovaly center_code a room_code. A také kořenový element company by mohl obsahovat ještě atribut s názvem společnosti. To vše je možné, když použijeme další anotace, které JAXB nabízí.
Anotace @XmlAccessorType říká, že každý field (nestatická a netransientní proměnná – to jsou v tomto příkladu všechny) bude svázán s xml elementem.
Anotaci @XmlElementWrapper použijeme, když pracujeme se seznamem. Vytvoříme element, který bude v sobě obsahovat jednotlivé elementy seznamu.
Anotace @XmlAttribute nevytvoří xml element, ale atribut. Pomocí hodnoty, kterou přiřadíme do name nastavíme atributu název.
Když použijeme anotaci @XmlElement, můžeme předat hodnotu name a tím nastavíme názvem xml elementu.
Jasnější to bude na příkladu.
App.java
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class App {
public static void main(String[] args) throws JAXBException {
// marshal
JAXBContext context = JAXBContext.newInstance(Company.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
File file = new File("company.xml");
// writes to file
marshaller.marshal(createCompany(), file);
// writes to System.out
marshaller.marshal(createCompany(), System.out);
// unmarshal
Unmarshaller unmarshaller = context.createUnmarshaller();
Company company = (Company)unmarshaller.unmarshal(file);
// print unmashalled object
System.out.println();
for (Center center : company.getCenters()) {
System.out.println(center.getCode() + " - " + center.getDescription());
for (Room room : center.getRooms()) {
System.out.println("room: " + room.getCode() + "\t number of seats: " + room.getNumberOfSeats());
}
System.out.println();
}
}
private static Company createCompany() {
Center metronomPrague = new Center();
metronomPrague.setCode("METPRG");
metronomPrague.setDescription("Office center Metronom in Prague");
metronomPrague.setRooms(
Arrays.asList(
new Room("A02", 14),
new Room("A13", 42),
new Room("B08", 22)));
Center aviaticaPrague = new Center();
aviaticaPrague.setCode("AVIPRG");
aviaticaPrague.setDescription("Office center Aviatica in Prague");
aviaticaPrague.setRooms(
Arrays.asList(
new Room("AA41", 70),
new Room("CA12", 38),
new Room("CA18", 24),
new Room("CB52", 88),
new Room("CD11", 62)));
Company company = new Company();
company.setName("1. Nájemní, s.r.o.");
company.setCenters(new ArrayList<>());
company.getCenters().add(metronomPrague);
company.getCenters().add(aviaticaPrague);
return company;
}
}
Company.java
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Company {
@XmlAttribute(name = "company_name")
private String name;
@XmlElement(name = "business_center")
@XmlElementWrapper(name = "business_centers")
private List<Center> centers;
// getters and setters
}
Oproti kódu z předchozího příspěvku jsem přidal field private String name a označil jej anotací @XmlAttribute(name = „company_name“), která vytvoří xml atribut s názvem company_name. V App.java přiřazujeme do proměnné name hodnotu „1. Nájemní, s.r.o“ takže v xml souboru to bude vypadat následovně:
<company company_name="1. Nájemní, s.r.o."> ... </company>
Anotace @XmlElementWrapper(name = „business_centers“) vytvoří xml element business_center a v něm budou obsaženy jako elementy všechny objekty ze seznamu. Anotace @XmlElement(name = „business_center“) nastaví název každého elementu v listu na business_center.
<business_centers>
<business_center>
...
</business_center>
<business_center>
...
</business_center>
</business_centers>
Center.java
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlType;
@XmlType
@XmlAccessorType(XmlAccessType.FIELD)
public class Center {
@XmlElement(name = "center_code")
private String code;
@XmlElement(name = "center_description")
private String description;
@XmlElementWrapper(name = "rooms")
@XmlElement(name = "room")
private List<Room> rooms;
// getters and setters
}
Anotace @XmlElement(name = „center_code“) nastaví xml elementu název center_code. Stejné je to pro @XmlElement(name = „center_description“).
<center_code>METPRG</center_code> <center_description>Office center Metronom in Prague</center_description>
Anotace @XmlElementWrapper(name = „rooms“) a @XmlElement(name = „room“) jsou obdobné jako ty, co jsme si vysvětlili na třídě Company.
Room.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
@XmlType
@XmlAccessorType(XmlAccessType.FIELD)
public class Room {
@XmlElement(name = "room_code")
private String code;
private int numberOfSeats;
public Room() {}
// setters and getters
}
V této třídě již není nic nového. Výsledný soubor vypadá následovně.
Company.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company company_name="1. Nájemní, s.r.o.">
<business_centers>
<business_center>
<center_code>METPRG</center_code>
<center_description>Office center Metronom in Prague</center_description>
<rooms>
<room>
<room_code>A02</room_code>
<numberOfSeats>14</numberOfSeats>
</room>
<room>
<room_code>A13</room_code>
<numberOfSeats>42</numberOfSeats>
</room>
<room>
<room_code>B08</room_code>
<numberOfSeats>22</numberOfSeats>
</room>
</rooms>
</business_center>
<business_center>
<center_code>AVIPRG</center_code>
<center_description>Office center Aviatica in Prague</center_description>
<rooms>
<room>
<room_code>AA41</room_code>
<numberOfSeats>70</numberOfSeats>
</room>
<room>
<room_code>CA12</room_code>
<numberOfSeats>38</numberOfSeats>
</room>
<room>
<room_code>CA18</room_code>
<numberOfSeats>24</numberOfSeats>
</room>
<room>
<room_code>CB52</room_code>
<numberOfSeats>88</numberOfSeats>
</room>
<room>
<room_code>CD11</room_code>
<numberOfSeats>62</numberOfSeats>
</room>
</rooms>
</business_center>
</business_centers>
</company>