undefined

Сложная сериализация в 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();

 Cat cat = (Cat) unmarshaller.unmarshal(reader);
}
Класс, объект которого десериализуется из XML
@XmlType(name = "zoo")
@XmlRootElement
class Zoo
{
 @XmlAny
 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;

 Cat()
 {
 }

Если коллекция помечена аннотацией @XmlAny, то в нее могут быть помещены любые подходящие объекты. 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.

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

Комментарии (43)
Чтобы просмотреть все комментарии или оставить свой,
перейдите в полную версию
barracuda 41 уровень, Санкт-Петербург Expert
4 февраля 2021
Ребята - составители лекций. Копипаст - это плохо. Набирайте весь код руками. У вас в первом примере в классе Dog - конструктор Cat. Так же, в том же примере, вот эту строку String xmldata = "<zoo><cat/><cat/><dog/><cat/></zoo>"; вы пытаетесь десериализовать в объект Cat : Cat cat = (Cat) unmarshaller.unmarshal(reader); Каким образом вы это пытались сделать? Давайте, соберитесь уже. Кроме того, на сайте oracle.com не нашёл аннотацию @XmlAny. За то там есть @XmlAnyElement...
Михаил 29 уровень, Смоленск
29 декабря 2020
Почему IntelliJ IDEA не знает @XmlAny?
Kex 38 уровень, Тольятти Expert
3 июля 2020
Меня мучал вопрос с первой лекции по XML в чем разница между атрибутом и элементом думал далее будет описано но не дождался, вообщем вот что выяснил: Проблемы атрибутов: атрибуты не могут содержать несколько полей (дочерние элементы могут) атрибуты не могут быть простым образом расширены в будущем атрибуты не могут описывать структуры (почти то же что и пункт 1й) атрибутами труднее манипулировать из программного кода атрибуты сложнее проверяются на предмет соответствия DTD Если вы используете атрибуты как контейнеры для данных, у вас рано или поздно возникнут проблемы с чтением и поддержкой документа. Старайтесь использовать элементы для данных. Используйте атрибуты только для предоставления информации, которая не относится к данным. Не делайте так. XML не для того придуман. <note day="12" month="11" year="2002" to="Tove" from="Jani" heading="Reminder" body="Don't forget me this weekend!"> </note>
Дмитрий 35 уровень, Самара
22 апреля 2020
Edffom 33 уровень, Мирный
22 апреля 2020
первый пример с ошибками, исправил но десериализация не пошла Exception in thread "main" java.lang.ClassCastException: class XML_annotation_any$Zoo cannot be cast to class XML_annotation_any$Cat , работает только если приводить к классу Zoo
Maksym Rado 29 уровень, Тернополь
1 марта 2020
"— Ух ты. Не могу представить, где мне это может понадобиться, но думаю, что это очень полезная штука. " @ Амиго У меня пока что про весь курс JR такое впечатление))
Boris 41 уровень Expert
29 января 2020
кто обяснит почему в этих примеров тэги не открываются и не закрываются?? что за каша ??


<data> // у этого есть закрываюший тэг он в конце
<items>  // у этого есть закрываюший тэг он предпоследний
 test 1
<item/>  // где у этого открывается???
 text 2
<item>
 name
</item>  // у этого тоже самое ести и открытие и закрытие
 text 3
</items>
</data>
как нормально понимать сколько тут обьектов?? и тут тоже самое

При этом последовательность тэгов «<zoo><cat/><cat/><dog/><cat/><zoo>» будет превращена в набор объектов Cat, Cat, Dog, Cat.
Vorlock 31 уровень, Днепр
12 января 2020
дока от oracle - самая нормальная по ощущениям Annotation Type XmlAnyElement
Дмитрий 37 уровень, Нижний Новгород
25 октября 2019
Про Enum в JAXB вспомнили, а в Jackson нет :\
Georgiy 41 уровень, Москва
11 сентября 2019
Почему в примере у класса Dog конструктор Cat() ?