— Привет, Амиго!
— Привет, Элли!
— Раз уж ты познакомился с 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).
Давай я покажу тебе рабочий пример, а потом мы его разберем:
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);
}
@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.
— А как будет выглядеть десериализация?
— Да почти так же, только короче:
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);
}
@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 | Ставится перед классом. Позволяет задать порядок полей для сериализации. |
— Как интересно. А есть еще?
— Есть много. Но не сейчас. Сейчас давай немного переделаем наш первый пример:
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);
}
@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?
— Да, десериализация будет работать как надо. Она умная.
— Что не может не радовать.
Спасибо за такую интересную лекцию, Элли.