Картографиране на динамичен JSON обект с Джаксън

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" } }

Съхраняваме динамичните свойства в обекта с подробности .

Можем да картографираме общите свойства със следния Java клас:

class Product { String name; String category; // standard getters and setters }

На всичкото отгоре се нуждаем от подходящо представяне за обекта с подробности . Например com.fasterxml.jackson.databind.JsonNode може да обработва динамични ключове .

За да го използваме, трябва да го добавим като поле към нашия Продуктов клас:

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. Използване на Map

Можем да разрешим този проблем, като използваме java.util.Map за полето за подробности . По-точно трябва да използваме Map .

Всичко останало може да остане същото:

class Product { // common fields Map 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")).isEqualTo("none");

4. Използване на @JsonAnySetter

Предишните решения са добри, когато обектът съдържа само динамични свойства. Понякога обаче имаме фиксирани и динамични свойства, смесени в един JSON обект .

Например може да се наложи да изгладим представянето на продукта:

{ "name": "Pear yPhone 72", "category": "cellphone", "displayAspectRatio": "97:3", "audioConnector": "none" }

Можем да третираме подобна структура като динамичен обект. За съжаление това означава, че не можем да дефинираме общи свойства - трябва да ги третираме и динамично.

Като алтернатива можем да използваме @JsonAnySetter, за да маркираме метод за обработка на допълнителни, неизвестни свойства . Такъв метод трябва да приема два аргумента: името и стойността на свойството:

class Product { // common fields Map details = new LinkedHashMap(); @JsonAnySetter void setDetail(String key, Object value) { details.put(key, value); } // standard getters and setters }

Имайте предвид, че трябва да създадем екземпляр на обекта details, за да избегнем NullPointerExceptions .

Тъй като съхраняваме динамичните свойства в карта , можем да ги използваме по същия начин, както преди:

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.