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

Сейчас я тебе расскажу об еще нескольких аспектах 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.

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