JavaRush /Курсы /Java Collections /Сложная сериализация в XML, JAXB (вложенные классы и т.д....

Сложная сериализация в XML, JAXB (вложенные классы и т.д.)

Java Collections
3 уровень , 9 лекция
Открыта

— Так вот. Как ты уже, наверное, догадался — это еще не все.

Сейчас я тебе расскажу об еще нескольких аспектах JAXB. Но начнем мы, как и в случае с JSON, с коллекций.

При десериализации коллекций в JAXB тоже возникает неопределенность, какую именно коллекцию (ArrayList, LinkedList, Vector, …) подставить в переменную типа List? И опять ответ на этот вопрос дают аннотации.

Тут все довольно просто. Если тип коллекции не задан в аннотации к ней, тогда JAXB попробует подобрать самую подходящую коллекцию – на основе типа. Для List это будет ArrayList, для Map – HashMap и т.д.

На самом деле тут гораздо меньше проблем, чем в случае с JSON, т.к. у каждого класса есть его уникальный тэг, а по тэгу можно точно определить – что это за класс.

Например, если надо десериализовать группу элементов, которые унаследованы от общего предка, для этого используется аннотация @XmlAny:

Конвертация объекта из XML
public static void main(String[] args) throws JAXBException
{
 String xmldata = "<zoo><cat/><cat/><dog/><cat/></zoo>";
 StringReader reader = new StringReader(xmldata);

 JAXBContext context = JAXBContext.newInstance(Cat.class, Zoo.class, Dog.class);
 Unmarshaller unmarshaller = context.createUnmarshaller();

 Zoo zoo = (Zoo) unmarshaller.unmarshal(reader);
}
Класс, объект которого десериализуется из XML
@XmlType(name = "zoo")
@XmlRootElement
class Zoo
{
 @XmlAnyElement
 public List<Object> animals;
}

@XmlType(name = "cat")
@XmlRootElement
class Cat
{
 public String name;
 public int age;
 public int weight;

 Cat()
 {
 }
}

@XmlType(name = "dog")
@XmlRootElement
class Dog
{
 public String name;
 public int age;
 public int weight;

 Dog()
 {
 }

Если коллекция помечена аннотацией @XmlAnyElement, то в нее могут быть помещены любые подходящие объекты. JAXB Unmarshaller при этом обращает внимание на тэги.

При этом последовательность тэгов «<zoo><cat/><cat/><dog/><cat/></zoo>» будет превращена в набор объектов Cat, Cat, Dog, Cat.

— Ожидаемо, в общем.

— Ага. О, кстати, вот еще что. Если ты десериализуешь смесь текста и тэгов, для этого надо использовать аннотацию @XmlMixed.

Пример такого XML:

Пример XML, для которого нужно использовать аннотацию @XmlMixed
<data>
<items>
 test 1
<item/>
 text 2
<item>
 name
</item>
 text 3
</items>
</data>

— Ого. А я и забыл, что такой XML бывает. Привык, что все так красиво, тэги вложены, все дела.

— Бывает. И даже на этот случай у JAXB есть аннотация!

— Отлично. А я вот, кстати, хотел спросить, а как сериализуются enum?

— Хороший вопрос! Молодец! Я-то как раз упустил эту тему.

Для enum существует специальная аннотация @XmlEnum, которой надо помечать enum. В ней же можно указать – будут значения представлены в виде чисел или строк.

Также есть специальная аннотация @XmlEnumValue, которая позволяет задать специальное значение, которое будет соответствовать данному значению enum’а.

Примеры:

Числа Строки
@XmlType @XmlEnum(Integer.class)
public enum Code 
{
 @XmlEnumValue("1") 
  START,

 @XmlEnumValue("2") 
  INPROGRESS,

 @XmlEnumValue("3") 
  FINISH

 @XmlEnumValue("-1") 
  ERROR
}
@XmlType @XmlEnum(String.class)
public enum Card 
{ 
 @XmlEnumValue("Пика")
  SPADES, 

 @XmlEnumValue("Бубна")
  DIAMONDS, 

 @XmlEnumValue("Черва")
  HEARTS, 

 @XmlEnumValue("Трефа")
  CLUBS 
}

— Ух ты. Не могу представить, где мне это может понадобиться, но думаю, что это очень полезная штука. А главное – не обязательно придерживается стандартных строковых или числовых значений.

— Ага. Это полезно, когда ты, например, пишешь программу, которая обменивается сообщениями, скажем, с сервером Facebook, и у них свой заданный набор значений. Тебе достаточно просто прописать их у своего enum и все заработает.

— Это же замечательно. Мне определенно нравится JAXB.

— Отлично. Тогда на сегодня все. Иди — отдыхай.

Комментарии (77)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
SomeBody098 Уровень 51
29 сентября 2024
прочитайте эту замечательную статью про xml, и ее продолжения
2 марта 2024
И что это? Вообще 0 объяснений , куда писать @XmlMixed? какой текст? Что происходит ?
Aglaya Уровень 47
17 июля 2022
Как произносится JAXB?
tohik Уровень 44
17 июля 2022
джаксб
Ilia lenskii Уровень 32
11 сентября 2022
Это же аббревиатура, а для них работает правило > буквенные аббревиатуры читаются по названию букв
Elidriel Уровень 35
25 марта 2022
Так... Ладно... из листания разных источников в интернете я понял что в современных реалиях чаще пользуются JSON, чем XML понятное дело, что с XML ознакомиться нужно, хотя бы чтобы знать что отвечать на собесах, но упираться в доскональное его изучение на мой взгляд смысла нет
Ilia lenskii Уровень 32
11 сентября 2022
Вы не видите всей картины. XML гораздо больше чем кажется, скажем HTML (подмножество XML), docx и прочие аналоги, SOAP в финансовом секторе.
Egor Уровень 51
22 января 2024
XML вижу в некоторых вакансиях на джуна. Лучше сначала XML осваивать
Anonymous #3241009 Уровень 43 Expert
17 марта 2024
если работаешь с электронным документооборотом то xml очень много, очень много фин отчетности отправляется xml
Denis Odesskiy Уровень 46
6 октября 2024
XML надо знать в обязательном порядке. Он намного гибче и универсальнее json и используется далеко не только в сериализации. jaxb тоже, пожалуй более мощный инструмент чем json (благодаря xml) позволяющий выполниять более глубокие настройки. json немного моднявие и хайповие (благодаря хайповости сегодня того же js) и чуточку легковеснее. Но это лишь мода, а она как известна временна и проходяща, потому знать надо и то и другое имхо...
hidden #2595317 Уровень 45
20 февраля 2022

Например, если надо десериализовать группу элементов, которые унаследованы 
от общего предка, для этого используется аннотация @XmlAny:
И хрен с ним, что класса Анимал нет вообще, но и никакого наследования не наблюдается.
Hidden #213 Уровень 48
6 марта 2022
угу... чем дальше, тем больше ошибок в лекциях😐 Такое чувство, что создатели JR просто выдохлись и забили на всё. Скопипастили код абы как... практически под каждой лекцией пишут об грубых ошибках (и этим постам уже по 3-4 года!)😖
Andrey Eliseev Уровень 41
20 мая 2022
Друзья, посмотрите внимательно дженерики в лист (List<Object> animals). Это значит что туда вообще все что угодно можно добавлять, а animals-просто его название)) я тоже сначала не увидел 😅
Виталий Уровень 47
17 февраля 2022
Последнее предложение чуть по-другому не прочитал. Было бы в контексте 😁
Kes Уровень 41
30 октября 2021
Анализирую лекцию
Дмитрий Уровень 41
1 июля 2021
Спасибо - нифига не понятно

При этом последовательность тэгов «<zoo><cat/><cat/><dog/><cat/><zoo>» будет превращена в набор объектов Cat, Cat, Dog, Cat.
почему zoo только открывающий тег? почему остальные теги - закрывающие?
Maks Panteleev Уровень 41
5 июля 2021
запись <cat/> равнозначна записи <cat></cat>, это пустой тег. Не надо путать <cat/> и </cat> )
Дмитрий Уровень 41
12 июля 2021
а что по zoo ?
Дмитрий Уровень 41
12 июля 2021
вижу, уже исправили )))
VitalyK #1116124 Уровень 39
21 июня 2021
скажите пожалуйста - тэг и элемент это одно и то же ?
Maks Panteleev Уровень 41
5 июля 2021
нет, тэг это тэг, а внутри тэга уже либо элемент либо атрибут либо все вместе либо ничего) как я понял, тэг = класс в джаве, а элементы и атрибуты это поля класса
Hidden #213 Уровень 48
6 марта 2022
Часто приходится Тэгать сейчас?😏
Maks Panteleev Уровень 41
6 марта 2022
примерно никогда)
Hidden #213 Уровень 48
6 марта 2022
😝 врёшь ты мне! Прямо сейчас наверное сидишь и тэгаешь
Maks Panteleev Уровень 41
6 марта 2022
а, так ты про онанизм? тогда да, часто конечно))))
Hidden #213 Уровень 48
6 марта 2022
Кто о чём😅😂 Я о граффити! Тэгать - рисовать граффити. Вандал🚫
Maks Panteleev Уровень 41
6 марта 2022
не, такое не делаю я) в школе ребята любили, а я никогда и баллончик то в руках не держал, хотя рэпчину слушал
Hidden #213 Уровень 48
6 марта 2022
хммм... очень странно🤨 Парень из столицы, слушал рэп\хип-хоп и что бы ни разу не держал баллончик в руках🤨 Вот 100% виноваты компуХтеры! или девушки! Одно из двух =D
Maks Panteleev Уровень 41
6 марта 2022
Я просто ненавижу рисовать, ваще не мое, поэтому самые долгие отношения в жизни оба раза были с художницами)))
Hidden #213 Уровень 48
6 марта 2022
Тянет к творческим людям? :) А они спрашивали у тебя: "А ты точно Программист?!" 🥰
Maks Panteleev Уровень 41
6 марта 2022
ты думаешь, что двое самых долгих отношений у меня уместились в один год примерно?)) потому что программистом я стал совсем недавно)) но нет, не тянет, это как будто бы карма)
15 июня 2021
Дополнение к лекции. JAXB напрямую не поддерживает java-интерфейсы (как и обобщенные типы). Поддерживается только интерфейс java.util.List и java.util.Map Если число реализаций интерфейса не велико и вероятность появления новых не очень высока, то удобно использовать аннотацию @XmlElements:

interface Animal {
}

@XmlRootElement
class Cat implements Animal {
    @XmlTransient public String name = "cat";
    @XmlTransient public int age;
    @XmlTransient public int weight;
}

@XmlRootElement
class Dog implements Animal {
    @XmlTransient public String name = "dog";
    @XmlTransient public int age;
    @XmlTransient public int weight;
}

@XmlRootElement
class Zoo {
    private Animal cat = new Cat();
    private Animal cat1 = new Cat();
    private Animal dog = new Dog();
    private Animal cat2 = new Cat();

    @XmlElements({
            @XmlElement(name = "cat", type = Cat.class),
            @XmlElement(name = "dog", type = Dog.class)
    })
    private List<Animal> animals = new ArrayList<>();

    Zoo() {
        animals.add(cat);
        animals.add(cat1);
        animals.add(dog);
        animals.add(cat2);
    }

    public static void main(String[] args) throws JAXBException, IOException {
        Zoo zoo = new Zoo();
        JAXBContext context = JAXBContext.newInstance(Zoo.class, Cat.class, Dog.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(zoo, System.out);
    }
}
продолжение в комментарии
15 июня 2021
В самом общем случае, как рекомендует документация, следует применять аннотацию @XmlRootElement вместе с @XmlAnyElement, что обеспечит большую гибкость в случае появления новых реализаций при большом количестве уже существующих.

//код

@XmlRootElement
class Zoo {
    private Animal cat = new Cat();
    private Animal cat1 = new Cat();
    private Animal dog = new Dog();
    private Animal cat2 = new Cat();

    @XmlAnyElement
    private List<Animal> animals = new ArrayList<>();

    Zoo() {
        animals.add(cat);
        animals.add(cat1);
        animals.add(dog);
        animals.add(cat2);
    }

   //код