— Не так швидко, юначе! У мене тобі ще дві лекції!

— Дві? Ого. Ну добре. Чого не зробиш заради власної крутості. Я готовий слухати.

— XML, як і JSON, часто застосовується при пересиланні даних між різними програмами та комп'ютерами. І так само є кілька фреймворків, які значно полегшують життя Java-програмістів при роботі з XML. Сьогодні я познайомлю тебе з одним із них.

JAXB – це чудовий багатофункціональний фреймворк для роботи з XML.

JAXB - 1

JAXB – це частина JDK, тому завантажувати його окремо не потрібно.

Давай я спочатку покажу тобі приклад роботи з ним, а потім ми його розберемо. Приклад:

Конвертація об'єкта в XML
< code>
public static void main(String[] args) throws JAXBException { //створення об'єкта для серіалізації в XML Cat cat = new Cat(); cat.name = "Murka"; cat.age = 5; cat.weight = 4; //писати результат серіалізації в Writer(StringWriter) StringWriter writer = new StringWriter(); //створення об'єкта Marshaller, який виконує серіалізацію JAXBContext context = JAXBContext.newInstance(Cat.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // сама серіалізація marshaller.marshal(cat, writer< /span>); //перетворюємо у рядок все записане в StringWriter String result = writer.toString(); System.out.println(result); }
Клас, об'єкт якого конвертує в XML
@XmlType(name = "cat") @XmlRootElement public class Cat { public String name; public int age; public int weight; public Cat() { } }
Результат серіалізації та виведення на екран:
<cat> <name>Murka </name> <age>5</age> <weight>4</weight> </cat>

— Щось мені цей код один на один нагадує серіалізацію в JSON. Теж анотації, але там був ObjectMapper, тут Context & Marshaller.

— Ага. Справді, вони дуже схожі. Jackson писався на зразок JAXB. Але й JAXB те саме з когось списали. Не можна вигадати щось геніальне на порожньому місці.

— Схоже на те.

— Ок, ось що там відбувається:

У рядках 5-8 ми створюємо об'єкт класу Cat і заповнюємо його даними.

Рядок 11 – створюємо об'єкт Writer для запису результату.

Сторок 14 – створюємо «контекст». Це аналог ObjectMapper, але від нього потім створюються ще два дочірні об'єкти Marshaller – для серіалізації, і Unmarshaller для десеріалізації . Невеликі відмінності від Jackson, але - неважливо. Рядок 15 - створюємо об'єкт Marshaller. Маршалінг – це синонім слова серіалізація.

Рядок 16 – встановлює властивість FORMATTED_OUTPUT у TRUE. У результат буде додано переноси рядка і пробіли, щоб код був читабельним для людини, а не весь текст в один рядок. Рядок 18 – серіалізація об'єкта. Рядки 21-22 – висновок результату серіалізації на екрані.

— А що це ще за анотації @XmlType(name = «cat») та @XmlRootElement?

@XmlRootElement вказує на те, що цей об'єкт може бути «коренем дерева» елементів у XML. Тобто. бути елементом найвищого рівня, всі інші елементи лежать у ньому.

@XmlType(name = «cat») вказує на те, що клас бере участь у JAXB серіалізації, в ній же задано ім'я, яке буде у XML-тегу для цього класу.

Добре, давай тепер покажу приклад десеріалізації з XML:

Конвертація об'єкта з XML
public static void main(String[] args) throws JAXBException { String xmldata = "<cat> <name>Murka</name><age>5</age>< /span><weight>4</weight></cat>""; StringReader reader = новий StringReader(xmldata); JAXBContext context = JAXBContext.newInstance(Cat.class); Unmarshaller unmarshaller = context.createUnmarshaller(); Cat cat = (Cat) unmarshaller. unmarshal(reader); }
Клас, об'єкт якого десеріалізується з XML
@XmlType(name = "cat") @XmlRootElement public class Cat { public String name; public int age; public int weight; public Cat() { } }

Все практично аналогічно випадку з Jackson. Але про всяк випадок поясню все, що тут відбувається.

Рядок 3 – задаємо рядок, який зберігає xml для десеріалізації.

Рядок 4 – обертаємо xml-рядок у StringReader.

Рядок 6 – створюємо JAXB-контекст, куди передаємо список класів.

Рядок 7 — створюємо Unmarshaller – об'єкт, який буде виконувати десеріалізацію.

Рядок 9 – десеріалізуємо xml з об'єкта reader і отримуємо об'єкт cat типу Cat.

— Тепер це все виглядає мало не очевидним. А ще кілька годин тому, я ламав голову — як це працює.

— Так завжди буває, коли стаєш розумнішим – складні речі стають простими.

— Я стаю розумнішим? Це не може не тішити.

— Чудово. Тоді ось тобі список анотацій, які ти можеш використовувати, щоб керувати результатом серії JAXB:

JAXB-анотації Опис
@XmlElement(name) Ставиться біля поля.
Поле буде представлено в XML-елементом.
Дозволяє задати ім'я для тега.
@XmlAttribute(name) Ставиться біля поля.
Поле буде представлено в XML-атрибутом!
Дозволяє задати ім'я для атрибута.
@XmlElementWrapper(nillable = true) Ставиться біля поля.
Дозволяє задати «обертаючий тег» для групи елементів.
@XmlType Ставиться біля класу.
Дозволяє задати метод для створення об'єкта, якщо конструктор за замовчуванням private.
@XmlJavaTypeAdapter Ставиться біля поля.
Дозволяє задати клас, який перетворюватиме дані поля в рядок.

— Як цікаво. А можна приклади з цими анотаціями, бо написане – це одне, а живий приклад – це зовсім інше.

— Ок. Буде тобі приклад. Хотів тільки додати, то JAXB дозволяє ставити анотації у методів getter/setter замість полів.

Обіцяний приклад:

Конвертація об'єкта в XML
< pre class="line-numbers language-java" data-line="" data-start="">public static void main(String[] args) throws JAXBException { //створення об'єктів Cat&Zoo для серіалізації в XML Cat cat = новий Cat(); cat.name = "Murka"; cat.age = 5; cat.weight = 4; Zoo zoo = новий Zoo(); zoo.animals.add(cat); zoo.animals.add(cat); //писати результат серіалізації в Writer(StringWriter) StringWriter writer = new StringWriter(); //створення об'єкта Marshaller, який виконує серіалізацію JAXBContext context = JAXBContext.newInstance(Cat.class , Zoo.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // самосеріалізація marshaller.marshal(zoo, writer); //перетворюємо все записане в StringWriter у рядок System.out.println(writer.toString()); }
Клас, об'єкт якого конвертує в XML
@XmlType(name = "zoo") @XmlRootElement public class Zoo { @XmlElementWrapper( name="wild-animals", nillable = true) @XmlElement(name = "tiger") public List animals = new ArrayList<>(); } public class Cat { @XmlElement(name = "catname") public String name; @XmlAttribute(name = "age")  public int age ; @XmlAttribute(name = "w") public int weight;  public Cat() { } }
Результат серіалізації та виведення на екран:
<zoo> <wild-animals> <tiger age="5" w="4"> <catname>Murka</catname> </tiger> <tiger age="5" w="4"> <catname>Murka</catname> </tiger> </wild-animals> </zoo>< /pre> 

Зверніть увагу: цього разу ми серіалізуємо не об'єкт Cat, а об'єкт типу Zoo, яких зберігає колекцію об'єктів Cat.

Об'єкт cat в колекцію був доданий двічі, тому він двічі в XML .

У колекції є свій тег – «wild-animals» , який обрамляє всі елементи колекції.

Елементи age & weight стали атрибутамиage & w.

За допомогою атрибуту @XmlElement ми змінили тег cat на tiger.

Зверни ще увагу на рядок 17, тепер ми передаємо в JAXB-контекст два класи - Zoo & Cat, т.к. вони обидва беруть участь у серіалізації.

— Сьогодні дуже цікавий день – стільки нового.

— Ага. Радий за тебе. Зараз зробимо невелику перерву і продовжимо.