Вы достигли нового уровня

Уровень 33

1. JavaScript

- Привет, Амиго!

- Привет, Билаабо!

- Рад тебя видеть. Сегодня у нас небольшое, но очень познавательное занятие. Сегодня я расскажу тебе о языке JavaScript.

- Новый язык? Как интересно…

- JavaScript сейчас популярен благодаря интернету. Дело в том, что это единственный язык, который умеют исполнять все браузеры. Если ты хочешь добавить анимацию или некоторую логику в свою интернет-страницу, то ты можешь сделать это с помощью JavaScript.

- А правда, что JavaScript – самый популярный язык?

- Да, но тут правильнее было бы сказать, что он самый популярный «второй язык». Программисты на C++, Java, C#, PHP вынуждены писать небольшие скрипты на JavaScript, чтобы оживить свои интернет-страницы. В то же время, людей, которые пишут только на JavaScript гораздо меньше.

- А почему у него такое название – JavaScript? Звучит почти как Java.

- На самом деле сначала он назывался LiveScript, но когда Java начала набирать популярность, его переименовали в JavaScript.

Java и JavaScript - это два совершенно разных языка, не стоит их путать.

JavaScript, в отличие от Java, не имеет классов, не поддерживает статическую типизацию, многопоточность и много чего еще. И если Java – это скорее большой набор строительных инструментов, то JavaScript – это швейцарский нож. JavaScript создан для решения маленьких задач, а Java – для больших и очень больших.

Вот тебе несколько фактов о JavaScript:

Факт первый – в JavaScript есть функции, но нет классов.

Вы просто пишите логику программы в нескольких функциях и все. Пример:

JavaScriptJava
function min(a, b)
{
 return a<b ? a: b;
}
public static int min(int a, int b)
{
return a<b ? a: b;
}

Новые функции объявляются с помощью конструкции «function+имя».

Еще пример:

JavaScriptJava
function min(a, b)
{
 return a<b ? a: b;
}

function main()
{
 var s = 3;
 var t = 5;
 var min = min(s, t);
}
public static int min(int a, int b)
{
 return a<b ? a: b;
}

public static void main()
{
 int s = 3;
 int t = 5;
 int min = min(s,t);
}

Факт второй – в JavaScript есть переменные, но у них нет типов.

JavaScript – это язык с динамической типизацией. Это значит, что у переменных, по факту, нет типов. Любой переменной можно присвоить значение любого типа (у значений типы есть). Пример:

JavaScriptJava
function main()
{
 var s = "Bender";
 var k = 1;
 var n = s.length;
}
public static void main()
{
 String s ="Bender";
 int k = 1;
 int n = s.length();
}

Но динамическая типизация увеличивает риск ошибок во время работы программы:

JavaScriptJava
function main()
{
 var s = "Bender";
 var k = 1;
 var n = k.length;
}
public static void main()
{
 String s ="Bender";
 int k = 1;
 int n = k.length();
}

В примере выше, мы подставили вместо s (строки), переменную k(число). В случае с Java ошибка будет обнаружена на этапе компиляции, в случае с JavaScript – позже: уже во время исполнения этого кода.

Если хочешь объявить переменную в JavaScript, надо написать «var+имя». Типов у переменных нет, так же нет типов у методов/функций и их аргументов.

В JavaScript очень мало строгих правил и очень много анархии.

Можно объявить функцию с 5 аргументами, а вызвать с двумя – остальные будут равны null. Можно объявить функцию с двумя аргументами, а при вызове передать пять. Три просто отпросятся. Контроль за ошибками, опечатками, изменениями – минимальный.

Факт третий – в JavaScript есть if, for, while

В JavaScript есть if, for, while и это – хорошая новость. Смотрим примеры:

JavaScriptJava
function main()
{
 var s = "Bender";

 var result = "";

 for(var i=0;i<s.length;i++)
 {
  result = s[i]+ "";
 }

 if(result.length>10)
 {
  alert (result);
 }
 else
 {
  while(result <=10)
  {
   result +="";
  }
  alert(result);
 }
}
public static void main()
{
 String s = "Bender";
 char[] s2 = s.toCharArray();
 String result = "";

 for(int i=0;i<s.length();i++)
 {
  result = s2[i]+ "";
 }

 if(result.length()>10)
 {
  System.out.println(result);
 }
 else
 {
  while(result <=10)
  {
   result +="";
  }
  System.out.println(result);
 }
}

- Довольно похоже. Думаю, я смог бы разобраться, как работает код, написанный на JavaScript.

- Оптимизм – это хорошо.

Факт четверный – в JavaSctipt есть try-catch-finally

В JavaScript есть исключения (Error) и это хорошо. checked исключений нет, только unchecked – аналог RuntimeException. try-catch-finally работает так же, как и в Java. Пример:

JavaScriptJava
function main()
{
 try
 {
  var s = null;
  var n = s.length;
 }
 catch(e)
 {
  alert(e);
 }
}
public static void main()
{
 try
 {
  String s = null;
  int n = s.length();
 }
 catch(Exception e)
 {
  System.out.println(e);
 }
}

При попытке узнать длину строки будет выкинуто исключение, т.к. переменная ссылается на null.

Факт пятый – в JavaScript есть массивы

Хорошая новость. В JavaScript есть массивы. Плохая – там нет ни списков, ни коллекций.

Еще одна хорошая новость – массивы могут динамически растягиваться, при добавлении новых элементов и уменьшаться при их удалении. Больше похоже на гибрид массива и списка.

Пример:

JavaScriptJava
function main()
{
 var m = [1,3,18, 45, 'c', "roma", null];
 alert(m.length); //7

 m.push("end");
 alert(m.length); //8

 for (var i=0;i<m.length;i++)
 {
  alert(m[i]);
 }
}
public static void main()
{
 List m = Arrays.asList(1,3,18, 45,'c', "roma", null);
 System.out.println(m.size());//7

 m.add("end");
 System.out.println(m.size());//8

 for (int i=0;i<m.size();i++)
 {
  System.out.println(m.get(i));
 }
}

- А что это за квадратные скобки при объявлении массива?

- Это и есть «объявление массива». Чтобы объявить массив надо написать квадратные скобки, а между ними перечислить элементы массива. Пустой массив объявляется просто парой скобок.

Пример
var m = [];

Факт шестой – в JavaSctipt есть объекты

В JavaScript есть объекты. На самом деле все в JavaScript является объектом, примитивные типы тоже. Каждый объект представлен в виде набора пар «ключ-значение». Грубо говоря, каждый объект JavaScript – это аналог HashMap в Java. Пример объявления объекта:

JavaScriptJava
function main()
{
 var m = {
  first_name : "Bill",
  last_name: "Gates",
  age: 54,
  weight: 67,
 children: ["Emma", "Catrin"],
 wife: {
  first_name : "Melinda",
  last_name: "Gates",
  age: 45,
  }
};

 alert(m.first_name); // Bill
 alert(m.age); // 54
 alert(m.wife.first_name);// Melinda

 m.age = 45;
 m.age++;
 m["first_name"] = "Stive";
 m["wife"] = null;
public static void main()
{
 HashMap m = new HashMap();
 m.put("first_name", "Bill");
 m.put("last_name", "Gates");
 m.put("age", 54);
 m.put("weight", 67);

 String[] children = {"Emma","Catrin"};
 m.put("children", children);

 HashMap wife = new HashMap();
 wife.put("first_name", "Melinda");
 wife.put("last_name", "Gates");
 wife.put("age", 45);
 m.put("wife", wife);

 System.out.println(m.get("first_name"));
 System.out.println(m.get("age"));

 HashMap w = ((HashMap)m.get("wife"));
 System.out.println(w.get("first_name")));

 m.put("age", 45);
 m.put("age", ((Integer)m.get("age"))+1);
 m.put("first_name","Stive");
 m.put("wife", null);

Чтобы создать новый объект достаточно написать две фигурные скобки «{}».

Внутри скобок можно указать данные объекта в формате «ключ, двоеточие, значение, запятая».

К полям объекта можно обращаться двумя способами:

Эквивалентные записи
m.age = 45;
m[“age”] = 45;

Если указанного поля нет, оно создается.

Что-то мой газовый пузырь переполнился, думаю надо сделать перерыв.

Напоследок - если хочешь изучить JavaScript подробнее, могу посоветовать отличный онлайн курс. Именно он когда-то вдохновил Джона на создание JavaRush:

http://www.codecademy.com/

Факт седьмой – JavaScript создан, чтобы работать внутри web-страниц.

2. JSON

- Ложная тревога – с пузырем все в порядке.

Продолжим. Сегодня я хочу рассказать тебе, что такое JSON.

- Да, я много раз слышал это слово, что же это такое?

- С развитием web-а, HTML-страницы с JavaScript начали активно взаимодействовать с серверами и загружать с сервера данные. Для облегчения этого процесса, был придуман стандарт обмена сообщениями между сервером и программой, написанной на JavaScript. Этот стандарт называется JSON (JavaScript Object Notation).

- И что же это за стандарт?

- О, тут самое интересное. В качестве стандарта было взято… объявление объекта в JavaScript!

Вот тебе пример сообщений в формате JSON:

Сообщения в формате JSON
{
 "name": "oleg",
 "last": "eremenko"
}
{
 "name": "batman",
 "enemies": [1,4,6,7,8,4,3,90]
}
{
 "name": "grandpa",
 "children": [
{
 "name" = "Bob",
 "children": ["Emma", "Nikol"]
},

{
 "name" = "Devid",
 "children": ["Jesica", "Pamela"]
}

]
}
{
 "12 45": {
 "__++": [],
 "1":"2"
 }
}
{}

- Т.е. они просто пересылают данные, которые фактически является объектами JavaScript?

- Ага. И это очень удобно по двум причинам:

Во-первых, не нужно конвертировать данные из «формата пересылки» в набор объектов JavaScript.

Во-вторых, такой формат очень нагляден: легко читается и редактируется человеком.

Конечно, есть некоторые ограничения – не все можно представить в виде набора объектов, массивов, текста и чисел.

Объект Date, например, пересылается в строковом виде: «2012-04-23T18:25:43.511Z»

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

- Как по мне - JSON очень простой формат, тут все очевидно и понятно.

Да и сам JavaScript не очень сложный.

- Язык-то простой, зато программы – сложные.

Или, как говорил мой дядя, в человеческом английском 26 букв, а вот научиться на нем правильно говорить – это не такая уж и простая задача для лобстера.

- Гм. Ты прав, Билаабо, буду иметь это в виду. Спасибо за интересную лекцию.

3. Сериализация в JSON

- Привет, Амиго!

- Привет, Элли!

- Раз уж ты познакомился с JSON, давай поговорим о нем сегодня подробнее.

- Ок. А где обычно он используется?

- Обычно дело выглядит так. Кто-то (клиент) запрашивает у Java-программы (сервера) данные. Программа создает Java-объекты и заполняет их информацией из базы данных. Затем преобразовывает их в формат понятный запрашивающему (клиенту), например JSON, и отсылает их обратно.

Давай я тебе расскажу, как работать с ним из Java. Собственно нам понадобится только две вещи – сериализовать Java-объекты в JSON-формат и десериализовать Java-объекты из формата JSON.

Т.е. JSON – это стандарт транспортировки сообщений/данных от одной программы до другой. Таких стандартов довольно много. Но если программа написана на JavaScript, она обычно старается работать с JSON.

- Ок. Я готов.

- Отлично. Тогда начнем.

Как ты уже знаешь, в Java есть встроенные стандартные средства сериализации. Но JSON к ним не относится. Поэтому если тебе надо использовать сериализацию объекта в JSON, ты можешь использовать один из популярных фреймворков(библиотек), которые это умеют.

- А чем отличаются различные фреймворки?

- Обычно они отличаются степенью сложности: есть фреймворки, которые умеют делать только самое необходимое, но они очень маленькие и простые. А есть и большие сложные фреймворки, которые могут делать гораздо больше.

Одним из популярных фреймворков считается Jackson. Мы рассмотрим работу с JSON на его примере.

Для начала тебе надо скачать этот фреймворк и добавить его себе в проект. Делать это надо в Intellij IDEA само собой. Скачать проект можно по ссылке.

- Готово.

- Отлично. Тогда продолжим.

Сконвертировать Java-объект в JSON примерно так же просто, как и сериализовать его. Для этого есть специальный класс ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper).

Давай я покажу тебе рабочий пример, а потом мы его разберем:

 Конвертация объекта в JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

public static void main(String[] args) throws IOException
{
 //создание объекта для сериализации в JSON
 Cat cat = new Cat();
 cat.name = "Murka";
 cat.age = 5;
 cat.weight = 4;

 //писать результат сериализации будем во Writer(StringWriter)
 StringWriter writer = new StringWriter();

 //это объект Jackson, который выполняет сериализацию
 ObjectMapper mapper = new ObjectMapper();

 // сама сериализация: 1-куда, 2-что
 mapper.writeValue(writer, cat);

 //преобразовываем все записанное во StringWriter в строку
 String result = writer.toString();
 System.out.println(result);
}
 Класс Cat, объект которого конвертирует в JSON
@JsonAutoDetect
class Cat
{
 public String name;
 public int age;
 public int weight;

 Cat()
 {
 }
}
 Результат сериализации и вывода на экран:
{ "name"="Murka", "age"=5, "weight"=4}

Вот как все было:

В строках 5-8 мы создаем объект класса Cat и заполняем его данными.

Строка 11 – создаем объект Writer, куда будем писать строку - JSON представление объекта.

Строка 14 – создаем объект ObjectMapper, который и выполняет всю сериализацию.

Строка 17 – пишем JSON-представление объекта cat во writer.

Строки 20-21 – выводим результат на экран.

Все выглядит довольно просто. Не сложнее родной сериализации в Java.

- А как будет выглядеть десериализация?

- Да почти так же, только короче:

 Конвертация объекта из JSON
1
2
3
4
5
6
7
8
9
10

public static void main(String[] args) throws IOException
{
 String jsonString = "{ \"name\"=\"Murka\", \"age\"=5, \"weight\"=4}";
 StringReader reader = new StringReader(jsonString);

 ObjectMapper mapper = new ObjectMapper();

 Cat cat = mapper.readValue(reader, Cat.class);
}
 Класс, объект которого десериализуется из JSON-формата
@JsonAutoDetect
class Cat
{
 public String name;
 public int age;
 public int weight;

 Cat()
 {
 }
}

Тут еще проще. Берем ObjectMapper и передаем в него строку с JSON или StringReader, а также класс объекта, который надо десериализовать. Вызываем метод readValue, и на выходе получаем готовый Java-объект со всеми данными.

- Ну, точно, как десериализация в Java.

- Почти. К объектам, которые сериализуются/десериализуются в JSON есть несколько требований:

1) поля должны быть видимые: или public или иметь getter’ы и setter’ы

2) должен быть конструктор по умолчанию (без параметров)

- Ясно. Ожидаемо, в общем. Хотя Java отлично сериализовала и private поля.

- Так то - Java. У нее есть доступ к скрытым данным. От себя не утаишь.

Тут есть еще третий аспект. Надеюсь, ты обратил внимание на аннотацию @JsonAutoDetect в классе Cat?

- Ага. Как раз хотел спросить – что это такое.

- Это аннотации – служебная информация для фреймворка Jackson. Можно очень гибко управлять результатом сериализации в JSON формат, расставляя правильные аннотации.

- Круто! А что за аннотации есть?

- Вот тебе несколько:

АннотацияОписание
@JsonAutoDetect Ставится перед классом.
Помечает класс как готовый к сериализациив JSON.
@JsonIgnore Ставится перед свойством.
Свойство игнорируется при сериализации.
@JsonProperty Ставится перед свойством или getter’ом или steer’ом. Позволяет задать другое имя поля при сериализации.
@JsonWriteNullProperties Ставится перед классом.
Поля объекта, которые равны null не будет игнорироваться.
@JsonPropertyOrder Ставится перед классом.
Позволяет задать порядок полей для сериализации.

- Как интересно. А есть еще?

- Есть много. Но не сейчас. Сейчас давай немного переделаем наш первый пример:

 Конвертация объекта в JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

public static void main(String[] args) throws IOException
{
 Cat cat = new Cat();
 cat.name = "Murka";
 cat.age = 5;
 cat.weight = 4;

 StringWriter writer = new StringWriter();

 ObjectMapper mapper = new ObjectMapper();

 mapper.writeValue(writer, cat);

 String result = writer.toString();
 System.out.println(result);
}
 Класс, объект которого конвертирует в JSON
@JsonAutoDetect
class Cat
{
 @JsonProperty(name="alias")
 public String name;

 public int age;

 @JsonIgnore
 public int weight;

 Cat()
 {
 }
}
 Результат сериализации и вывода на экран:
{ "alias"="Murka", "age"=5}

Код остался тот же, но я поменял аннотации: указал другое имя полю name - имя alias. А так же отметил поле weight как Ignore, в результате JSON объекта поменялся.

- Хорошо, что можно так всего настраивать – думаю, мне это обязательно пригодится.

А десериализация поймет, как с этим работать? При десериализации из JSON в Java-объект, значение поля alias будет занесено в name объекта Cat?

- Да, десериализация будет работать как надо. Она умная.

- Что не может не радовать.

Спасибо за такую интересную лекцию, Элли.

4. Json serialize frameworks

- Привет, дружище!

- Здорова, Диего.

- Я тут смотрю, тебя познакомили с азами сериализации в JSON?

- Почему с азами? Я уже много знаю!

- Святая простота. Да ты и половины не знаешь. Процентов 10 от силы.

- Ух ты. А что там еще осталось?

- Десериализация иерархии объектов (полиморфизм при десериализации), десериализация коллекций, еще много всего. Jackson – большой и мощный фреймворк, а ты с ним познакомился чуть-чуть, прямо говоря.

- Ладно. Тогда расскажи мне про что-нибудь из этого, а я – послушаю.

Приятно становиться умнее с каждой лекцией!

- Как не помочь другу-роботу? Кто если не я?

Готов? Тогда слушай.

Как ты уже убедился, аннотации используются не только при сериализации, но и при десериализации. На практике для сериализации надо гораздо меньше информации, чем для десериализации. Пример:

Java classJSON
class Cat
{
 public String name = "murka";
 public Cat[] cats = new Cat[0];
}
{
 "name": "murka",
 "cats": []
}
class Cat
{
 public String name = "murka";
 public List<Cat> cats = new ArrayList<Cat>();
}
{
 "name": "murka",
 "cats": []
}
class Cat
{
 public String name = "murka";
 public List<Cat> cats = new LinkedList<Cat>();
}
{
 "name": "murka",
 "cats": []
}

Объекты типов Array(массив), ArrayList, LinkedList,… заменяются на массив в JSON-формате.

А вот при десериализации неясно, какой объект создать ArrayList или LinkedList?

- Согласен, если у класса есть поле, и тип поля – это интерфейс (как в случае с public List<Cat> cats), то совсем не ясно, какой именно объект ему присваивать.

- Можно добавить этому полю дополнительные аннотации или указать нужные классы прямо во время десериализации объекта. Смотри пример:

 Конвертация объекта в JSON
1
2
3
4
5
6
7
public static void main(String[] args) throws IOException
{
 String jsonString = "{ \"name\"=\"Murka\", \"age\"=5, \"weight\"=4}";
 StringReader reader = new StringReader(jsonString);
 ObjectMapper mapper = new ObjectMapper();
 Cat cat = mapper.readValue(reader, TypeFactory.collectionType(ArrayList.class, Cat.class));
}
 Класс, объект которого десериализуется из JSON-формата
@JsonAutoDetect
class Cat
{
 public String name;
 public List<Cat> cats = new ArrayList<Cat>();

 Cat()
 {
 }
}

Т.е. мы в метод mapper.readValue вторым параметром передаем список классов, которые будут использоваться при десериализации.

- А мне нравится. Удобно. Можно где надо десериализовать «JSON массив» как ArrayList, а где надо, как LinkedList.

Ты еще говорил, что аннотациями можно. Это как?

- Да ничего сложного. Пример:

 Конвертация объекта в JSON
1
2
3
4
5
6
7
8
9
10

public static void main(String[] args) throws IOException
{
 String jsonString = "{ \"name\"=\"Murka\", \"age\"=5, \"weight\"=4}";
 StringReader reader = new StringReader(jsonString);

 ObjectMapper mapper = new ObjectMapper();

 Cat cat = mapper.readValue(reader, Cat.class);
}
 Класс, объект которого десериализуется из JSON-формата
11
12
13
14
15
16
17
18
19
20
21
22

@JsonAutoDetect
class Cat
{
 public String name;
 @JsonDeserialize(as=ArrayList.class)
 public List<Cat> cats = new ArrayList<Cat>();

 Cat()
 {
 }
}

В строке 16 мы просто добавили аннотацию @JsonDeserialize(as=ArrayList.class), где указали, какую реализацию интерфейса List использовать.

- Ага. Ясно. Действительно – довольно просто.

- Но и это еще не все. Теперь представь, что тип данных в List тоже интерфейс! Что ты будешь делать?

- У нас есть аннотация и на этот случай?

- Да, причем, та же самая. В ней можно указать еще и тип параметр. Выглядеть это будет вот так:

Тип коллекцииКак задать тип данных
List @JsonDeserialize(contentAs=ValueTypeImpl.class)
Map @JsonDeserialize(keyAs=KeyTypeImpl.class)

- Круто. Действительно, много нужных аннотация для разных случаев, о которых заранее и не догадаешься.

- И это еще не все. Сейчас будет самое вкусное. В реальных проектах, классы данных очень часто унаследованы от одного базового класса или интерфейса, который используется практически везде. И вот представь, тебе надо десериализовать структуру данных, которая содержит такие классы. Пример:

 Конвертация объекта в JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

public static void main(String[] args) throws IOException
{
 Cat cat = new Cat();
 cat.name = "Murka";
 cat.age = 5;

 Dog dog = new Dog();
 dog.name = "Killer";
 dog.age = 8;
 dog.owner = "Bill Jeferson";

 ArrayList<Pet> pets = new ArrayList<Pet>();
 pets.add(cat);
 pets.add(dog);

 StringWriter writer = new StringWriter();
 ObjectMapper mapper = new ObjectMapper();
 mapper.writeValue(writer, pets);
 System.out.println(writer.toString());
}
 Класс, объект которого конвертирует в JSON
@JsonAutoDetect
class Pet
{
 public String name;
}

@JsonAutoDetect
class Cat extends Pet
{
 public int age;
}

@JsonAutoDetect
class Dog extends Pet
{
 public int age;
 public String owner;
}
 Результат сериализации и вывода на экран:
[
 { "name" : "Murka", "age" : 5},
 { "name": "Killer", "age" : 8 , "owner" : "Bill Jeferson"}
]

Обрати внимание на результат сериализации.

Мы не сможем провести десериализацию этих данных обратно в Java-объекты, т.к. они фактически неразличимы.

- Немного различимы - у Dog есть поле owner.

- Да, но это поле может быть равно null или вообще пропускаться при сериализации.

- А разве мы не можем задать тип данных с помощью известных нам аннотаций?

- Нет. В одной коллекции после десериализации должны хранится различные объекты типа Cat, Dog и еще пары десятков классов, которые можно унаследовать от Pet.

- И что же можно тут сделать?

- Тут применяют две вещи.

Во-первых, выделяют некоторое поле, которое используется для того, чтобы отличать один тип от другого. Если его нет – его заводят.

Во-вторых, есть специальные аннотации, которые позволяют управлять процессом «полиморфной десериализации». Вот что можно сделать:

 Конвертация объекта в JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) throws IOException
{
 Cat cat = new Cat();
 cat.name = "Murka";
 cat.age = 5;

 Dog dog = new Dog();
 dog.name = "Killer";
 dog.age = 8;
 dog.owner = "Bill Jeferson";

 House house = new House();
 house.pets.add(dog);
 house.pets.add(cat);

 StringWriter writer = new StringWriter();
 ObjectMapper mapper = new ObjectMapper();
 mapper.writeValue(writer, house);
 System.out.println(writer.toString());
}
 Класс, объект которого конвертирует в JSON
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property="type")
@JsonSubTypes({
@JsonSubTypes.Type(value=Cat.class, name="cat"),
@JsonSubTypes.Type(value=Dog.class, name="dog")
})

class Pet
{
 public String name;
}

class Cat extends Pet
{
 public int age;
}

class Dog extends Pet
{
 public int age;
 public String owner;
}

class House
{
 public List<Pet> pets = new ArrayList<Pet>();
}
 Результат сериализации и вывода на экран:
{
 "pets" : [
 {"type" : "dog","name" : "Killer", "age" : 8, "owner" : "Bill Jeferson"},
 {"type" : "cat","name" : "Murka", "age" : 5}
]
}

С помощью аннотаций мы указываем, что JSON-представление будет содержать специальное поле type, которое будет хранить значение cat, для класса Cat и значение dog, для класса Dog. Этой информации достаточно, чтобы выполнить корректную десериализацию объекта: при десериализации по значению поля type будет определяться тип объекта, который надо создать.

Иногда в качестве значения поля type используют имя класса (например, "com.example.entity.Cat.class"), но это не очень хорошо. Зачем стороннему приложению, которому мы пересылаем JSON, знать, как называются наши классы? К тому же, классы иногда переименовывают. Использование некоего уникального имени для обозначения конкретного класса – предпочтительнее.

- Круто! А я и не знал, что десериализация такая сложная вещь. И что столько всего можно настраивать.

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

- Амиго – крутой программист. Круто!

- Ладно. Иди, отдыхай.

5. Задачи

Задачи
1. Первая сериализация в JSON

НЕОБХОДИМО: подключенные библиотеки Jackson Core, Bind и Annotation версии 2.6.1

1) В программе не выполнено основное требование к сериализации в JSON.
Найдите ошибку и исправьте.
2) Расставьте правильно Json аннотации у классов.
Все данные должны сериализоваться.
2. Вторая сериализация в JSON

НЕОБХОДИМО: подключенные библиотеки Jackson Core, Bind и Annotation версии 2.6.1

Расставьте Json аннотации так, чтобы результат работы метода main был следующим
{"wildAnimal":"Murka","over":3}
3. Десериализация JSON объекта

НЕОБХОДИМО: подключенные библиотеки Jackson Core, Bind и Annotation версии 2.6.1

В метод convertFromJsonToNormal первым параметром приходит имя файла, который содержит один ДЖЕЙСОН объект.
Вторым параметром приходит имя класса, объект которого находится в файле.
Метод convertFromJsonToNormal должен вычитать объект из файла, преобразовать его из JSON и вернуть его.
4. Конвертация из одного класса в другой используя JSON

НЕОБХОДИМО: подключенные библиотеки Jackson Core, Bind и Annotation версии 2.6.1

Два класса имеют одинаковые поля, но не имеют общий суперкласс. Пример, классы First и Second.
Реализовать логику метода convertOneToAnother, который должен возвращать объект класса resultClassObject, значения полей которого равны значениям полей в объекте one.
Известно, что у классов есть Json аннотация, у которой значение проперти равно имени класса в нижнем регистре.
На примере класса First, это className="first"
Классы First и Second не участвуют в тестировании, они предоставлены в качестве тестовых данных.
5. Определение имени класса

НЕОБХОДИМО: подключенные библиотеки Jackson Core, Bind и Annotation версии 2.6.1

Расставьте Json аннотации так, чтобы результат выполнения метода main был следующий:
{
  "className" : ".Parking",
  "name" : "Super Parking",
  "city" : "Kyiv",
  "autos" : [ {
      "className" : "com.javarush.test.level33.lesson05.home05.RaceBike",
      "name" : "Simba",
      "owner" : "Peter",
      "age" : 2
  }, {
      "className" : "com.javarush.test.level33.lesson05.home05.Motorbike",
      "name" : "Manny",
      "owner" : null
  }, {
      "className" : "com.javarush.test.level33.lesson05.home05.Car"
  } ]
}

Подсказка: это всего два класса

6. XML, Сериализация в XML

- Как делишки?

- Отлично. Не жалуюсь. Сегодня Билаабо рассказал про JavaScript. Не все, конечно, но тоже немало. Я конечно еще на JS ничего не писал, но думаю, что это не сложно.

А Элли рассказала про сериализацию в JSON. И ты рассказывал о Jackson framework и как настраивать «полиморфную десериализацию» с помощью аннотаций.

- Нифига себе, ты умный теперь, Амиго! Серьезный мужик!

- А то!

- Ладно. Давай к работе. Сегодня новая и интересная тема – XML.

XML – это стандарт представления данных, которые легко могут быть прочитаны человеком, и еще легче – программой. Пример xml-файла:

XML
<data>
<owner first="Nikolay" last="Ivanovich">
<address>Moscow</address>
</owner>
<cat name="Murka" age="15"/>
</data>

Основа XML – это теги. Тег – это слово в треугольных скобках (знаки меньше и больше).

Теги бывают открывающие и закрывающие. Одному открывающему всего соответствует один закрывающий тег. Открывающие теги могут иметь атрибуты.

В тег можно складывать другие теги, получая, таким образом, дерево элементов. Тег верхнего уровня называют корнем (root): у него есть дочерние теги, у них свои дочерние теги.

Примеры:

ТегОписание
<data> Открывающий тег «data»
</data> Закрывающий тег «data»
<cat name="Murka"age="15"> Тег с атрибутами. Значения атрибутов берутся в кавычки
<data>
<owner>
<cat name="Murka"/>
</owner>
</data>
Вложенные теги.
<cat name="Murka" age="15"/> Автозакрывающийся тег.
Такому тегу не нужен закрывающий.
Не может содержать дочерние теги.
<info>
Тут может быть любая информация
</info>
Тег может содержать текстовые данные
<info>
Тут может
<data xxx="yyy">
</data>
быть любая
<data 2xxx="yyy"/>
информация
</info>
Тег может содержать текстовые данные и другие теги вперемешку.

- Выглядит несложно. А какие теги бывают?

- Любые. Никаких зарезервированных тегов нет. XML – это язык, для описания любых данных. Люди сами придумывают теги для своих нужд и договариваются, как их использовать.

Фактически, XML – это способ записать данные в виде дерева элементов, понятный компьютеру.

- Вроде ясно. Кстати, у меня вопрос.

Вот JSON используется для передачи данных с браузера на сервер, а где используется XML?

- Да там же, где и JSON: для хранения и передачи данных.

Ладно, продолжим.

Представь, что есть один общий XML-файл, который хранит данные программы, которую пишут двадцать человек. Тогда каждый из них придумывает теги для себя и очень скоро они начинают мешать друг другу.

Чтобы гарантировать уникальность тегов, им были придуманы префиксы. Выглядит это так:

ТегиОписание
<animal:cat> Тег cat с префиксом animal
<animal:cat>
</animal:cat>
<zoo:cat>
</zoo:cat>
Два тега cat с разными префиксами.
<animal:cat zoo:name="MX"> Тег cat с префиксом animal, атрибут name с префиксом zoo.

Префиксы еще называют namespace – пространство имен. Тогда последнее предложение в таблице будет звучать так «Тег cat из пространства имен animal с атрибутом name из пространства имен zoo».

Кстати, помнишь в Java у класса есть короткое имя, а есть длинное уникальное имя, в которое входит название пакета, его еще указывают при импорте?

- Ага.

- Так вот, у префиксов тоже есть уникальное длинное имя и его тоже указывают при импорте:

Пример
<data xmlns:soap="http://cxf.apache.org/bindings/soap">
<soap:item>
<soap:info/>
</soap:item>
</data>

«xmlns:soap» значит «XML-namespace SOAP»

Более того, если есть теги без префикса, можно задать и его уникальное имя:

Пример
<data xmlns="http://www.springframework.org/schema/beans"
xmlns:soap="http://cxf.apache.org/bindings/soap"
xmlns:task="http://www.springframework.org/schema/task">
<soap:item>
<soap:info/>
<task:info/>
</soap:item>
</data>

«xmlns=…» задает namespace для пустого префикса – т.е. для тегов без префикса, таких как data.

В документе может быть сколько угодно namespace, но у каждого должно быть свое уникальное имя.

- Ясно. А почему такие странные «уникальные имена» у этих namespace?

- Обычно там указывают URL, по которому находится документ, который описывает этот namespace и/или его XML-теги.

- Не так уж и мало на меня сегодня вылили информации. Что еще?

- Еще немного осталось.

Во-первых, у XML есть заголовок – специальная строка, которая описывает версию этого XML и кодировку файла. Выглядит она обычно так:

Выглядит она обычно так:

Пример
<?xml version="1.0" encoding="UTF-8"?>
<data xmlns:soap="http://cxf.apache.org/bindings/soap">
<soap:item>
<soap:info/>
</soap:item>
</data>

Еще в XML можно вставлять комментарии. Для начала комментария используют «<!--», а для конца «-->».

Пример
<?xml version="1.0" encoding="UTF-8"?>
<data xmlns:soap="http://cxf.apache.org/bindings/soap">
<soap:item>
<!-- <soap:info/> -->
</soap:item>
<!-- это тоже комментарий -->
</data>

- Пока понятно.

- Из-за того, что в XML используются символы « < > “ &», их нельзя использовать в других местах. Для их описания используют так называемые «эскейп последовательности» - набор символов для представления других символов/символа. Вот список некоторых из них:

Escape-последовательностьСимвол, который она заменяет
&amp; &
&quot; "
&lt; <
&gt; >
&apos;

А вот пример кода, который хранится в XML:

Java-кодОн же, в XML
if (a<b)
System.out.println("a is minimum");
<code>
if (a &lt; b)
 System.out.println(&quot;a is minimum&quot;);
</code>

- М-да. Выглядит не очень красиво.

- А ты помнишь, в Java тоже экранируются некоторые символы - например «\». И тоже для его написания в строке приходится писать его дважды. Так что это часто встречаемое явление.

- Ок.

- У меня на сегодня все.

- Ура. Наконец-то я отдохну.

7. JAXB

- Не так быстро, молодой человек! У меня для тебя еще две лекции!

- Две? Ого. Ну, ладно. Чего не сделаешь ради собственной крутости. Я готов слушать.

- XML, как и JSON, часто применяется при пересылке данных между разными программами и компьютерами. И так же есть несколько фреймворков, которые значительно упрощают жизнь Java-программистов при работе с XML. Сегодня я познакомлю тебя с одним из них.

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

JAXB – это часть JDK, поэтому скачивать его отдельно не требуется.

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

 Конвертация объекта в XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

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);

 //преобразовываем в строку все записанное в StringWriter
 String result = writer.toString();
 System.out.println(result);
}
 Класс, объект которого конвертирует в XML
@XmlType(name = "cat")
@XmlRootElement
class Cat
{
 public String name;
 public int age;
 public int weight;

 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
1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) throws JAXBException
{
 String xmldata =
"<cat><name>Murka</name><age>5</age><weight>4</weight></cat>";
 StringReader reader = new StringReader(xmldata);

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

 Cat cat = (Cat) unmarshaller.unmarshal(reader);
}
 Класс, объект которого десериализуется из XML
@XmlType(name = "cat")
@XmlRootElement
class Cat
{
 public String name;
 public int age;
 public int weight;

 Cat()
 {
 }
}

Все практически аналогично случаю с Jackson. Но на всякий случай объясню все, что тут происходит.

Строка 4 – задаем строку, которая хранит xml для десериализации.

Строка 5 – оборачиваем xml-строку в StringReader.

Строка 7 – создаем JAXB-контекст, куда передаем список классов.

Строка 8 - создаем Unmarshaller – объект, который будет выполнять десериализацию.

Строка 10 – десериализуем xml из объекта reader и получаем объект cat типа Cat.

- Теперь это все выглядит чуть ли не очевидно. А еще пару часов назад, я ломал голову - как же это работает.

- Так всегда бывает, когда становишься умнее – сложные вещи становятся простыми.

- Я становлюсь умнее? Это не может не радовать.

- Отлично. Тогда вот тебе список аннотаций, которые ты можешь использовать, чтобы управлять результатом результатом JAXB сериализации:

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

- Как интересно. А можно примеры с этими аннотациями, а то написанное – это одно, а живой пример – это совсем другое.

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

Обещанный пример:

Конвертация объекта в XML
public static void main(String[] args) throws JAXBException
{
 //создание объектов Cat&Zoo для сериализации в XML
 Cat cat = new Cat();
 cat.name = "Murka";
 cat.age = 5;
 cat.weight = 4;

 Zoo zoo = new Zoo();
 zoo.animals.add(cat);
 zoo.animals.add(cat);

 //писать результат сериализации будем во Writer(StringWriter)
 StringWriter writer = newStringWriter();

 //создание объекта 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
class Zoo
{
 @XmlElementWrapper(name="wild-animals", nillable = true)
 public List<Cat> animals = new ArrayList<Cat>
}


@XmlType(name = "tiger")
class Cat
{

 @XmlElement(name = "catname")
 public String name;
 @XmlAttribute(name = "age")
 public int age;
 @XmlAttribute(name = "w")
 public int weight;

 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>

Обрати внимание, в этот раз мы сериализуем не объект Cat, а объект типа Zoo, которых хранит коллекцию объектов Cat.

Объект cat в коллекцию был добавлен дважды, поэтому он 2 раза в XML.

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

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

С помощью атрибута @XmlType мы поменяли тэг cat на tiger.

Обрати еще внимание на строку 18, теперь мы передаем в JAXB-контекст два класса – Zoo & Cat, т.к. они оба участвуют в сериализации.

- Сегодня очень интересный день – столько нового.

- Ага. Рад за тебя. Сейчас сделаем небольшой перерыв и продолжим.

8. Задачи

Задачи
1. Первая сериализация в XML

Раставьте правильно JAXB аннотации у статических классов.
Метод main не участвует в тестировании.
2. Десериализация XML объекта

В метод convertFromXmlToNormal первым параметром приходит строка, содержащая xml объект.
Вторым параметром приходит имя класса, объект которого необходимо вернуть.
Метод convertFromXmlToNormal должен создать объект из xml-строки и вернуть его.

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

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

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

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

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

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

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

 Конвертация объекта из XML
1
2
3
4
5
6
7
8
9
10
11
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
<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("Пика")
  CLUBS,

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

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

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

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

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

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

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

10. Задачи

Задачи
1. Создание класса по строке xml

Восстановите класс по переданной строке xml.
Класс должен быть в отдельном файле.
Метод getClassName должен возвращать восстановленный класс.
Метод main не участвует в тестировании.
2. Комментарий внутри xml

Реализовать метод toXmlWithComment, который должен возвращать строку - xml представление объекта obj.
В строке перед каждым тэгом tagName должен быть вставлен комментарий comment.
Сериализация obj в xml может содержать CDATA с искомым тегом. Перед ним вставлять комментарий не нужно.

Пример вызова: toXmlWithComment(firstSecondObject, "second", "it's a comment")
Пример результата:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<first>
<!--it's a comment-->
<second>some string</second>
<!--it's a comment-->
<second>some string</second>
</first>

11. Учимся гуглить

- Вот тебе несколько заданий:

 Что надо найти в Google
1 Что такое JSON
2 В чем связь JSON и JavaScript
3 Как использовать Jackson
4 Java jackson. Как настроить сериализацию в JSON
5 Настройка JAXB
6 Сериализация в JAXB примеры
7 Аннотации в JAXB
8 Документация по Jackson
9 Документация по JAXB
10 Проблемы десериализации в Jackson

12. Профессор дает доп. материал

- Привет, Амиго!

Вот тебе дополнительный материал по теме.

Ссылка на дополнительный материал

13. Хулио

- Привет, Амиго!

- Привет, Хулио.

- Ты купил на обед Json? Ой, я хотел сказать батон.

- Купил. Но кажется мне, кому - то нужно отдохнуть. Присаживайся.

Оригинал видео на YouTube

14. Вопросы к собеседованию по этой теме

- Привет, Амиго!

 Вопросы к собеседованиям
1 Что такое JSON?
2 В чем отличия Java и JavaScript?
3 В чем отличия JSON и XML?
4 Какие фреймворки для работы с JSON вы знаете?
5 Какие фреймворки для работы с XML вы знаете?
6 Какие аннотации Jackson вы знаете?
7 Какие аннотации JAXB вы знаете?
8 В чем отличие сериализации и десериализации в JSON?
9 Что лучше JSON или XML? Почему?
10 Что такое DTO?

15. Большая задача

- Привет, боец!

- Поздравляю тебя с повышением уровня квалификации. Нам нужны отчаянные парни.

- Уверен, у тебя есть еще много нерешенных задач. Самое время решить парочку из них!