Использование Jackson
#
Васильев Андрей Михайлович, 2024
Версии презентации
Библиотека Jackson
#
Представляет собой набор инструментов для обработки данных на JVM-платформе
- Позволяет считывать и записывать данные в JSON-формате
- Предоставляет средства для удобной работы с объектами классов
- Содержит средства для работы с другими форматами данных: BSON, CSV, Protobuf,
TOML, YAML, XML и т.д.
- Является именно набором связных и бинарно совместимых инструментов, а не
единым большим проектом
- Поставляется под лицензией Apache 2.0, разрешающей коммерческое
использование
Полезные ссылки:
Потоковая обработка
#
Основой для эффективной обработки JSON-документов является ядро библиотеки,
которое предоставляет средства для потоковой обработки данных
- Обработка документа выполняется за один проход
- Используется минимальный объём памяти
Подключение библиотеки
#
В список зависимостей приложения необходимо добавить Maven-артефакт:
"com.fasterxml.jackson.core:jackson-core:2.17.2"
Документацию по классам библиотеки можно посмотреть
https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.17.2/index.html
Ключевые объекты
#
JsonFactoryBuilder
— строитель фабрики ключевых объектов
JsonFactory
— фабрика объектов для считывания или записи
JsonGenerator
— генератор JSON, создаётся отдельно для каждого документа
JsonParser
— считыватель JSON, создаётся отдельно для каждого документа
С помощью JsonFactoryBuilder можно настроить общие параметры путём включения и
выключения
- JacksonReadFeature, опций по считыванию данных
- JacksonWriteFeature, опций по записи данных
Создание генератора JSON
#
Фабрика JsonFactory предоставляет ряд методов для создания генератора, который
сможет записать свои данные: в выходной поток, файл, объект приёма данных
Помимо целевого объекта этим методам также можно передать кодировку данных
Для создания генератора, записывающего данные на стандартный поток вывода
достаточно:
val factory: JsonFactory = JsonFactoryBuilder().build()
val outputGenerator: JsonGenerator = factory.createGenerator(System.out)
outputGenerator.prettyPrinter = DefaultPrettyPrinter()
По окончании формировании JSON-документа необходимо вызвать метод close()
Потоковая запись JSON
#
При формировании JSON-документа необходимо последовательно описывать состояние
целевого JSON-документа, включая все его компоненты
- Символ начала массива,
writeStartArray()
- Символ окончания массива,
writeEndArray()
- Символ начала объекта,
writeStartObject()
- Символ окончания объекта,
writeStartObject()
- Название поля,
writeFieldName(name)
- Строковое значение,
writeString(value)
- Числовое значение,
writeNumber(value)
- Логическое значение,
writeBoolean(value)
- Null-значение,
writeNull()
- Удобные методы для записи пары ключ-значение,
writeNumberField(name, value)
Пример записи простого объекта
#
Создадим следующий JSON-документ с потоковой записью данных
{
"sides" : [ 5, 3, 4 ],
"color" : "RED",
"cool" : true
}
with(outputGenerator) {
writeStartObject()
writeFieldName("sides")
writeStartArray()
writeNumber(5)
writeNumber(3)
writeNumber(4)
writeEndArray()
writeFieldName("color")
writeString("RED")
writeBooleanField("cool", true)
writeEndObject()
close()
}
Объектное представление
#
Потоковая запись данных является самым быстрым и эффективным способом
формирования JSON-документов
Однако каждый документ можно соотнести к некоторой сложной структурой данных
внутри приложения, которая включает в себя множество сложных полей и их значений
Модуль jackson-databind предоставляет соответствующие средства, позволяющие
решить данную задачу. Данный модуль рассчитан на использование с ЯП Java
Для поддержки данной функциональности в Kotlin на платформе JVM используйте
модуль jackson-module-kotlin:
com.fasterxml.jackson.module:jackson-module-kotlin:2.17.+
Средство отображения объектов
#
Для выполнения преобразования Kotlin-объекта в JSON-документ и наоборот
необходимо создать компонент отображения объектов, ObjectMapper:
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
val mapper = jacksonObjectMapper()
Для работы также необходимо определить класс данных Kotlin, который будет
формировать данные
data class Triangle(val sideA: Double, val sideB: Double, val sideC: Double)
Создадим на основе объекта данного класса соответствующий JSON-документ:
val triangle = Triangle(3.0, 4.0, 5.0)
mapper.writeValue(System.out, triangle)
Получим следующий вывод:
{"sideA":3.0,"sideB":4.0,"sideC":5.0}
Отображение Kotlin в JSON
#
Компонент отображения объектов использует рефлексию, чтобы получить список
свойств объекта, их типы и значения
- Если тип данных есть одновременно и в Kotlin, и в JSON, то при выводе он будет
использован (null, логический тип, число, строка)
- Сложные объекты будут преобразованы в строковое представление
- Значением ключа будет являться название свойства преобразуемого объекта
Можно использовать аннотации для настройки поведения компонента отображения
Список доступных аннотаций и их воздействие на отображение данных можно
прочитать в
https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-annotations/2.17.2/index.html
Также стоит отметить аннотации для поддержки классов описания дат
https://github.com/FasterXML/jackson-modules-java8
Переименовывание свойств
#
data class Pseudo(
@JsonProperty("Money")
val info: Int,
)
val mapper = jacksonObjectMapper()
mapper.enable(SerializationFeature.INDENT_OUTPUT)
println(mapper.writeValueAsString(Pseudo(10)))
Результат работы кода:
Какой интерфейс использовать
#
- Низкоуровневый интерфейс предоставляет самый эффективный способ по
преобразованию данных в рамках данного набора библиотек
- Низкоуровневый интерфейс требует написания кода, отсутствует поведение «по
умолчанию»
- Компонент преобразования данных использует рефлексию, т.е. каждый раз тратится
время на анализ структуры преобразуемого объекта
- Для модификации поведения необходимо разбираться в доступных аннотациях
- Аннотации могут предоставляться в отдельных библиотеках и разработаны
самостоятельно
- Для написания аннотаций надо понимать структуру низкоуровневого интерфейса
- Невозможно сделать два представления для одного объекта с помощью компонента
преобразования данных
- Операции преобразования из JSON в объекты Kotlin значительно сложнее при
использовании низкоуровневого интерфейса