Элементы JSON с нумерацией как частью имени элемента

У меня есть образец JSON следующим образом. Я должен сопоставить этот объект с другим форматом JSON, каноническим для пользовательского интерфейса (получение разных заказов от разных поставщиков и объединение их в общий формат пользовательского интерфейса).

Если я сгенерирую POJO, он создаст классы Order_1, Order_2... под внешним классом, который выглядит грязным. А во время разработки я не могу предвидеть, сколько заказов может прийти в пиковый период. Так как мне подойти к этой проблеме?

Мой конечный результат должен быть в состоянии сопоставить этот JSON с целевым JSON, где повторяемые элементы являются массивами.

{
    "TotalOrders": 6,
    "Order_1": {
        "Item_1": {
            "item": "Shirt",
            "Quantity": 2
        },
        "Item_2": {
            "item": "Jeans",
            "Quantity": 2
        }

    },
    "Order_2": {
        "Item_1": {
            "item": "Caps",
            "Quantity": 2
        },
        "Item_2": {
            "item": "Bags",
            "Quantity": 2
        },
        "Item_3": {
            "item": "Chains",
            "Quantity": 2
        }
    },
    "Order_3": {
        "Item_1": {
            "item": "Watches",
            "Quantity": 2
        },
        "Item_2": {
            "item": "Rings",
            "Quantity": 2
        },
        "Item_3": {
            "item": "Perfumes",
            "Quantity": 2
        },
        "Item_4": {
            "item": "Deo",
            "Quantity": 1
        }
    },
    "Order_4": {
        "Item_1": {
            "item": "Cans",
            "Quantity": 2
        },
        "Item_2": {
            "item": "Tubes",
            "Quantity": 2
        },
        "Item_3": {
            "item": "Tents",
            "Quantity": 2
        }
    },
    "Order_5": {
        "Item_1": {
            "item": "Butter",
            "Quantity": 2
        },
        "Item_2": {
            "item": "Jam",
            "Quantity": 2
        },
        "Item_3": {
            "item": "Bread",
            "Quantity": 2
        }
    },
    "Order_6": {
        "Item_1": {
            "item": "DVD",
            "Quantity": 2
        },
        "Item_2": {
            "item": "Floppy",
            "Quantity": 2
        },
        "Item_3": {
            "item": "Cables",
            "Quantity": 2
        }
    }
}

1 ответ

Это можно решить с помощью специального десериализатора. Тем не менее, вам нужно будет проанализировать JSON в модели дерева Джексона, и я нахожу работу с моделью дерева и Джексона JsonNode очень громоздко и не интуитивно понятно

Таким образом, альтернативой является использование функции Джексона anySetter, которая представляет собой аннотированный метод, который получит все "неизвестные" свойства. Преимущество по сравнению с пользовательским десериализатором заключается в том, что вы уже разобрали json в Map, это намного легче пройти и обработать.

Вот пример, который будет анализировать любое количество заказов и предметов в POJO с массивами. Я использовал массивы, так как с ними проще работать, когда доступ осуществляется через индексы.

import java.io.*;
import java.util.*;
import java.util.stream.*;

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;

public class OrderList
{
    private Order[] orders = null;
    @JsonProperty("TotalOrders")
    private int totalOrders = -1;

    public static class Order
    {
        private OrderedItem[] items = null;

        public OrderedItem[] getItems() { return items; }

        @Override
        public String toString()
        {
            return "Order:" + Arrays.toString(getItems());
        }
    }

    public static class OrderedItem
    {
        public String item;
        public int quantity;

        public OrderedItem() {}
        public OrderedItem(String item, int quantity)
        {
            setItem(item);
            setQuantity(quantity);
        }

        public String getItem() { return item; }
        public void setItem(String newItem) { item = newItem; }

        public int getQuantity() { return quantity; }
        public void setQuantity(int newQty) { quantity = newQty; }

        @Override
        public String toString()
        {
            return "OrderedItem:{" + getItem() + "," + getQuantity() + "}";
        }
    }

    // all properties exepct totalOrders will be directed here
    @SuppressWarnings("unchecked")
    @JsonAnySetter
    public void setOrders(String key, Object value)
    {
        // initialize orders array according to totalOrders
        if (orders == null  &&  totalOrders > 0) orders = new Order[totalOrders];
        // parse order idx from property name
        int parseOrderIdx = -1;
        if (key != null  &&  key.startsWith("Order_")) {
            parseOrderIdx = Integer.parseInt(key.split("_")[1]);
        }
        if (orders == null  ||  parseOrderIdx < 1  ||  parseOrderIdx > orders.length) {
            System.err.println("ERROR in parsing totalOrders and/or order idx");
            return;
        }

        // java requires final variable to be used in lambda expr.
        final int orderIdx = parseOrderIdx;
        orders[orderIdx-1] = new Order();
        // value arg is map of items
        Map<String, Object> items = (Map<String, Object>)value;
        orders[orderIdx-1].items = new OrderedItem[items.size()];
        IntStream.rangeClosed(1, items.size()).forEach(itemIdx -> {
            Map<String, Object> item = (Map<String, Object>)items.get("Item_" + itemIdx);
            if (item == null) {
                System.err.println("ERROR in parsing item Item_" + itemIdx + " order Order_" + orderIdx);
                return;
            }
            orders[orderIdx-1].items[itemIdx-1] =
                    new OrderedItem((String)item.get("item"), (Integer)item.get("Quantity"));
        });
    }

    public static void main(String[] args)
    {
        ObjectMapper mapper = new ObjectMapper();
        try (InputStream is = new FileInputStream("C://Temp/xx.json")){
            OrderList ol = mapper.readValue(is, OrderList.class);
            System.out.println(Arrays.toString(ol.orders));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Другие вопросы по тегам