Jackson ObjectMapper

Модуль 2. Java Core
16 уровень , 5 лекция
Открыта

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);
}
Комментарии (22)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Руслан Уровень 48
11 января 2026
лекция топчик!!
19 декабря 2024
Не знаю почему, но я в восторге от лекции!
Руслан Никитин Уровень 109
17 октября 2024
Для не понимающих зачем так много и что оно обозначает Основные зависимости 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 Уровень 109 Expert
24 сентября 2024
Не забываем добавить все библиотеки из лекции. з.ы. можно сделать папку в корне явараша проекта и закинуть все файлы туда. а в библиотеках просто добавить путь до этой папки.
Тимур Уровень 109
25 сентября 2024
Да уж... По нормальному их лучше прописывать в зависимостях через pom.xml. Но так как в проекте JR его не наблюдается, делаем всё ручками 👐, как описано в начале лекции.
Олег Уровень 106 Expert
22 июля 2024
Ну оно как бы в целом понятно, но недостаточно, чтобы решить задачи.
Руслан Уровень 115
4 марта 2024
Почему пишется в таком формате? - !<lion> name: "Алекс" roarVolume: 5.5 А не в таком: - lion name: "Алекс" roarVolume: 5.5 Кто-нибудь знает?
Андрей Уровень 79
20 ноября 2023
Павел Уровень 19 Expert
15 ноября 2023
Пока решил первую задачу. Использовал jackson отсюда. Необходимо добавить все шесть файлов jar в библиотеки, а не два, как говорится в задаче.
Данил Уровень 115 Expert
24 июня 2023
Перед решением задачи про зоопарк, рекомендую прочитать данную страницу https://javascopes.com/jackson-annotations-7a1a88eb/?ysclid=ljabbpxy4o949545497
Anonymous #3613348 Уровень 46
28 января 2026
Статья для решения и правда хороша. Чтоб быстрее тыкалось: тыц
jvatechs Уровень 111 Expert
2 апреля 2023
Актуальные на 02.04.2023 библиотеки (ver. 2.15.0-rc2): https://www.mediafire.com/folder/bb1f1jde1c5bp/JacksonMapper