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

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

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

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

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

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

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

— Ок. Я готов.

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

Сериализация в JSON - 1

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

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

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

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

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

— Готово.

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

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

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

Конвертация объекта в JSON
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}

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

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

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

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

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

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

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

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

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

Конвертация объекта из JSON
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’ом или setter’ом. Позволяет задать другое имя поля при сериализации.
@JsonPropertyOrder Ставится перед классом.
Позволяет задать порядок полей для сериализации.

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

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

Конвертация объекта в JSON
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("alias")
 public String name;
 public int age;
 @JsonIgnore
 public int weight;

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

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

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

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

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

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

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