Автор оригинала: Attila Fejér.
1. введение
Работа с предопределенными структурами данных JSON с помощью Jackson проста. Однако иногда нам нужно обрабатывать динамические объекты JSON, которые имеют неизвестные свойства .
В этом коротком уроке мы рассмотрим несколько способов отображения динамических объектов JSON в классы Java.
Обратите внимание, что во всех тестах мы предполагаем, что у нас есть поле ObjectMapper типа com.fasterxml.jackson.databind.ObjectMapper .
Дальнейшее чтение:
Сопоставление вложенных значений с Джексоном
Использование опционально с Джексоном
2. Использование JsonNode
Допустим, мы хотим обработать спецификации продукта в интернет-магазине. Все продукты имеют некоторые общие свойства, но есть и другие, которые зависят от типа продукта.
Например, мы хотим знать соотношение сторон дисплея мобильного телефона, но это свойство не имеет большого смысла для обуви.
Структура данных выглядит следующим образом:
{ "name": "Pear yPhone 72", "category": "cellphone", "details": { "displayAspectRatio": "97:3", "audioConnector": "none" } }
Мы храним динамические свойства в объекте details .
Мы можем сопоставить общие свойства со следующим классом Java:
class Product { String name; String category; // standard getters and setters }
Кроме того, нам нужно соответствующее представление для объекта details . Например, com.fasterxml.jackson.databind.JsonNode может обрабатывать динамические ключи .
Чтобы использовать его, мы должны добавить его в качестве поля в наш класс Product :
class Product { // common fields JsonNode details; // standard getters and setters }
Наконец, мы проверяем, что это работает:
String json = ""; Product product = objectMapper.readValue(json, Product.class); assertThat(product.getName()).isEqualTo("Pear yPhone 72"); assertThat(product.getDetails().get("audioConnector").asText()).isEqualTo("none");
Однако у нас есть проблема с этим решением. Наш класс зависит от библиотеки Джексона, так как у нас есть поле JsonNode .
3. Использование карты
Мы можем решить эту проблему с помощью java.util.Карта для поля подробности . Точнее, мы должны использовать Map Object> . Object>
Все остальное может остаться прежним:
class Product { // common fields Mapdetails; // standard getters and setters }
И тогда мы сможем проверить это с помощью теста:
String json = ""; Product product = objectMapper.readValue(json, Product.class); assertThat(product.getName()).isEqualTo("Pear yPhone 72"); assertThat(product.getDetails().get("audioConnector")).isEqualTo("none");
4. Использование @JsonAnySetter
Предыдущие решения хороши, когда объект содержит только динамические свойства. Однако иногда у нас есть фиксированные и динамические свойства, смешанные в одном объекте JSON .
Например, нам может потребоваться выровнять представление нашего продукта:
{ "name": "Pear yPhone 72", "category": "cellphone", "displayAspectRatio": "97:3", "audioConnector": "none" }
Мы можем рассматривать подобную структуру как динамический объект. К сожалению, это означает, что мы не можем определить общие свойства — мы также должны обрабатывать их динамически.
В качестве альтернативы мы могли бы использовать @JsonAnySetter для обозначения метода обработки дополнительных неизвестных свойств . Такой метод должен принимать два аргумента: имя и значение свойства:
class Product { // common fields Mapdetails = new LinkedHashMap<>(); @JsonAnySetter void setDetail(String key, Object value) { details.put(key, value); } // standard getters and setters }
Обратите внимание, что мы должны создать экземпляр объекта details , чтобы избежать NullPointerExceptions .
Поскольку мы храним динамические свойства в Map , мы можем использовать его так же, как и раньше:
String json = ""; Product product = objectMapper.readValue(json, Product.class); assertThat(product.getName()).isEqualTo("Pear yPhone 72"); assertThat(product.getDetails().get("audioConnector")).isEqualTo("none");
5. Создание пользовательского десериализатора
В большинстве случаев эти решения работают просто отлично. Однако иногда нам нужно гораздо больше контроля. Например, мы могли бы хранить информацию о десериализации наших объектов JSON в базе данных.
Мы можем ориентироваться на эти ситуации с помощью пользовательского десериализатора. Поскольку это сложная тема, мы рассмотрим ее в другой статье, начиная с пользовательской десериализации в Джексоне .
6. Заключение
В этой статье мы рассмотрели несколько способов обработки динамических объектов JSON с помощью Jackson.
Как обычно, примеры доступны на GitHub .