Jackson ObjectMapper

Открыта

Jackson — это популярная библиотека для сериализации/десериализации Java-объектов в различные текстовые форматы. Основной функционал для работы с форматом JSON — класс ObjectMapper. А работать с другими форматами помогут его наследники (XmlMapper, YAMLMapper). Благодаря наследованию работа со всеми форматами будет происходить единообразно, через единый интерфейс.

Качаем jar-ники

Перед тем, как изучить примеры, нужно скачать jar-файлы Jackson-а и подключить их к проекту в IntellijIDEA. Рассмотрим, как искать нужные файлы на примере jackson-databind:

  1. Перейди на сайт Maven Repository.

  2. В поисковую строку введи “jackson-databind”, получишь результат:

  3. Нас интересует первый результат поиска, переходим по ссылке.

  4. Иногда может потребоваться конкретная версия библиотеки, чтобы обеспечить совместимость с другими компонентами проекта. Тебе подойдет последняя версия (на момент написания лекции это 2.13.2.2), переходи по ссылке.

  5. На открывшейся странице тебе нужна ссылка “bundle”:

  6. Скачиваем jar-файл по ссылке.

Аналогично можно найти и скачать остальные необходимые jar-ники:

Скачав все необходимые файлы, подключи их к проекту в IntellijIDEA:

  1. Открой настройки проекта (это можно сделать комбинацией Ctrl+Alt+Shift+S).

  2. Перейди в Libraries.

  3. Жми +, затем Java, выбери все скачанные файлы. Должно получиться так:

  4. На этом подготовка закончена, будем пробовать ObjectMapper в деле.

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

Сначала сериализуем какой-нибудь объект в JSON:

import com.fasterxml.jackson.databind.ObjectMapper;

class Book {
	public String title;
	public String author;
	public int pages;
}

public class Solution {
	public static void main(String[] args) throws Exception {
    	Book book = new Book();
    	book.title = "Обитаемый остров";
    	book.author = "Стругацкий А., Стругацкий Б.";
    	book.pages = 413;

    	ObjectMapper mapper = new ObjectMapper();
    	String jsonBook = mapper.writeValueAsString(book);
    	System.out.println(jsonBook);
	}
}

Запустив main, получишь такой вывод:

{"title":"Обитаемый остров","author":"Стругацкий А., Стругацкий Б.","pages":413}

У ObjectMapper-а есть много дополнительных настроек. Воспользуемся одной из них, чтобы JSON-строка была удобочитаемо отформатирована. После создания объекта ObjectMapper выполним команду:

mapper.enable(SerializationFeature.INDENT_OUTPUT);

Информация в выводе осталась та же, но добавились отступы и переносы строк:

{
  "title" : "Обитаемый остров",
  "author" : "Стругацкий А., Стругацкий Б.",
 "pages" : 413
}

Десериализация из JSON

Теперь выполним обратное действие: десериализуем строку в объект. Чтобы можно было оценить работу программы, в класс Book добавим метод toString:

@Override
public String toString() {
	return "Book{" +
        	"title='" + title + '\'' +
        	", author='" + author + '\'' +
        	", pages=" + pages +
        	'}';
}

И выполним такой main:

public static void main(String[] args) throws Exception {
	String jsonString = "{\"title\":\"Обитаемый остров\",\"author\":\"Стругацкий А., Стругацкий Б.\",\"pages\":413}";
	Book book = new ObjectMapper().readValue(jsonString, Book.class);
	System.out.println(book);
}

Вывод:

Book{title='Обитаемый остров', author='Стругацкий А., Стругацкий Б.', pages=413}

Метод readValue перегружен, у него есть много вариаций, принимающих файл, ссылку, различные потоки чтения и т. д. Для упрощения в нашем примере использован вариант, принимающий JSON в виде строки.

Как уже говорилось выше, ObjectMapper имеет много настроек, рассмотрим некоторые из них.

Игнорируем неизвестные свойства

Рассмотрим ситуацию, когда у JSON-строки есть свойство, которого нет в классе Book:

public static void main(String[] args) throws Exception {
	String jsonString = """
        	{
          	"title" : "Обитаемый остров",
          	"author" : "Стругацкий А., Стругацкий Б.",
          	"pages" : 413,
          	"unknown property" : 42
        	}""";
	ObjectMapper mapper = new ObjectMapper();
	Book book = mapper.readValue(jsonString, Book.class);
	System.out.println(book);
}

Попытавшись выполнить этот код, получим UnrecognizedPropertyException. Такое поведение установлено по умолчанию, но мы можем его изменить:

ObjectMapper mapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

При создании объекта ObjectMapper используем метод configure, чтобы установить нужную настройку в false. Метод configure изменяет объект, у которого его вызвали, и возвращает этот же объект, поэтому его можно вызывать и по-другому:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

По функциональности такая запись аналогична предыдущей.

Если теперь запустить main, десериализация пройдет успешно, а unknown property будет проигнорировано.

Удобные аннотации

Jackson предоставляет нам ряд аннотаций для всесторонней кастомизации сериализации. Рассмотрим несколько самых полезных:

@JsonIgnore — ставится над элементом, который нужно игнорировать при сериализации/десериализации:

class Book {
	public String title;
	@JsonIgnore
	public String author;
	public int pages;
}

В результате при сериализации поле author не попадет в результирующий JSON. При десериализации поле author получит значение по умолчанию (null), даже если в JSON-е было другое значение.

@JsonFormat — позволяет задать формат сериализованных данных. Добавим в класс Book еще одно поле типа Date:

class Book {
	public String title;
	public String author;
	public int pages;
	public Date createdDate = new Date();
}

После сериализации получим такой JSON:

 {
  "title" : "Обитаемый остров",
  "author" : "Стругацкий А., Стругацкий Б.",
  "pages" : 413,
  "createdDate" : 1649330880788
}

Как видишь, дата сериализировалась в виде числа. Добавим аннотацию и зададим формат:

class Book {
	public String title;
	public String author;
	public int pages;
	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
	public Date createdDate = new Date();
}

Теперь результат сериализации:

{
  "title" : "Обитаемый остров",
  "author" : "Стругацкий А., Стругацкий Б.",
  "pages" : 413,
  "createdDate" : "2022-04-07"
}

@JsonProperty — позволяет изменить имя свойства, в которое будет сериализировано поле. Еще этой аннотацией можно помечать методы, и их возвращаемое значение будет преобразовано в JSON-свойство при сериализации:

class Book {
	@JsonProperty("name")
	public String title;
	public String author;
	public int pages;

	@JsonProperty("quotedTitle")
	public String getQuotedTitle() {
    	    return "«" + title + "»";
	}
}

Результат сериализации:

{
  "author" : "Стругацкий А., Стругацкий Б.",
  "pages" : 413,
  "name" : "Обитаемый остров",
  "quotedTitle" : "«Обитаемый остров»"
}

@JsonInclude — с помощью этой аннотации можно указать, в каком случае поле должно сериализироваться. Можно добавлять как отдельным полям, так и всему классу. Сначала попробуем сериализовать объект с неинициализированными полями:

public class Solution {
	public static void main(String[] args) throws Exception {
    		Book book = new Book();

    		ObjectMapper mapper = new ObjectMapper();
    		mapper.enable(SerializationFeature.INDENT_OUTPUT);
    		String jsonBook = mapper.writeValueAsString(book);
    		System.out.println(jsonBook);
	}
}

Результат сериализации:

{
  "title" : null,
  "author" : null,
  "pages" : 0
}

А если добавить аннотацию:

@JsonInclude(JsonInclude.Include.NON_NULL)
class Book {
	public String title;
	public String author;
	public int pages;
}

То получим результат:

{
  "pages" : 0
}

Теперь поля, имеющие значение null, не сериализовались.

@JsonPropertyOrder — позволяет задать порядок сериализации полей:

@JsonPropertyOrder({"author", "title", "pages"})
class Book {
	public String title;
	public String author;
	public int pages;
}

Результат сериализации:

{
  "author" : "Стругацкий А., Стругацкий Б.",
  "title" : "Обитаемый остров",
  "pages" : 413
}

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

Сериализация и десериализация в XML

Если нужно сериализовать в XML-формат, можем использовать все те же настройки и аннотации. Единственным отличием будет реализация объекта mapper:

public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "Обитаемый остров";
	book.author = "Стругацкий А., Стругацкий Б.";
	book.pages = 413;

	ObjectMapper mapper = new XmlMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String xmlBook = mapper.writeValueAsString(book);
	System.out.println(xmlBook);
}

Вывод:

 <Book>
  <title>Обитаемый остров</title>
  <author>Стругацкий А., Стругацкий Б.</author>
  <pages>413</pages>
</Book>

Десериализация XML:

public static void main(String[] args) throws Exception {
   String xmlString = """
            <Book>
             <title>Обитаемый остров</title>
             <author>Стругацкий А., Стругацкий Б.</author>
             <pages>413</pages>
           </Book>""";
   ObjectMapper mapper = new XmlMapper();
   Book book = mapper.readValue(xmlString, Book.class);
   System.out.println(book);
}

Сериализация и десериализация в YAML

Аналогично XML действуем и с YAML:

public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "Обитаемый остров";
	book.author = "Стругацкий А., Стругацкий Б.";
	book.pages = 413;

	ObjectMapper mapper = new YAMLMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String yamlBook = mapper.writeValueAsString(book);
	System.out.println(yamlBook);
}

Вывод:

---
title: "Обитаемый остров"
author: "Стругацкий А., Стругацкий Б."
pages: 413

Десериализация YAML:

public static void main(String[] args) throws Exception {
   String yamlString = """
           ---
           title: "Обитаемый остров"
           author: "Стругацкий А., Стругацкий Б."
           pages: 413""";
   ObjectMapper mapper = new YAMLMapper();
   Book book = mapper.readValue(yamlString, Book.class);
   System.out.println(book);
}
Комментарии (20)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Руслан
Уровень 48
11 января, 12:43
лекция топчик!!
19 декабря 2024, 19:38
Не знаю почему, но я в восторге от лекции!
17 октября 2024, 09:56
Для не понимающих зачем так много и что оно обозначает Основные зависимости Jackson 1. jackson-databind: Основная библиотека для сериализации и десериализации объектов в JSON и обратно. 2. jackson-annotations: Содержит аннотации, которые помогают управлять сериализацией и десериализацией. 3. jackson-core: Основной компонент Jackson, который предоставляет базовые функции для работы с JSON. 4. jackson-dataformat-xml: Расширение для работы с XML. Позволяет сериализовать и десериализовать объекты в XML и обратно. 5. jackson-dataformat-yaml: Расширение для работы с YAML. Позволяет сериализовать и десериализовать объекты в YAML и обратно. Зависимости для работы с XML 6. woodstox-core: Современная реализация StAX, которая поддерживает Stax2 API. Это необходимо, чтобы избежать проблем с отсутствием методов, таких как writeRaw. 7. stax2-api: Библиотека, которая предоставляет интерфейсы Stax2. Это может быть полезно, если вы хотите использовать дополнительные функции Stax2.
I'm Siberian Trust me, i'm an engineer Expert
24 сентября 2024, 13:36
Не забываем добавить все библиотеки из лекции. з.ы. можно сделать папку в корне явараша проекта и закинуть все файлы туда. а в библиотеках просто добавить путь до этой папки.
Тимур
Уровень 109
25 сентября 2024, 17:20
Да уж... По нормальному их лучше прописывать в зависимостях через pom.xml. Но так как в проекте JR его не наблюдается, делаем всё ручками 👐, как описано в начале лекции.
Олег
Уровень 106
Expert
22 июля 2024, 20:00
Ну оно как бы в целом понятно, но недостаточно, чтобы решить задачи.
Руслан
Уровень 115
4 марта 2024, 17:59
Почему пишется в таком формате? - !<lion> name: "Алекс" roarVolume: 5.5 А не в таком: - lion name: "Алекс" roarVolume: 5.5 Кто-нибудь знает?
Андрей
Уровень 79
20 ноября 2023, 12:08
Павел
Уровень 19
Expert
15 ноября 2023, 22:00
Пока решил первую задачу. Использовал jackson отсюда. Необходимо добавить все шесть файлов jar в библиотеки, а не два, как говорится в задаче.
jvatechsBackend Developer в Ищу стажировкуExpert
2 апреля 2023, 02:45
Актуальные на 02.04.2023 библиотеки (ver. 2.15.0-rc2): https://www.mediafire.com/folder/bb1f1jde1c5bp/JacksonMapper
Виктория
Уровень 111
4 марта 2023, 10:11