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.