2017-05-06 29 views
0

我有一个示例JSON,如下所示。我必须将这个对象映射到另一个JSON格式,该格式对UI是规范的(从不同供应商获得不同的命令并将它们聚合到一个通用的UI格式)。具有编号作为元素名称一部分的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 
     } 
    } 
} 

回答

0

这可以使用custom deserializer来解决。但是,您需要将json解析为Jackson's tree model,我发现使用树模型和Jackson的JsonNode非常繁琐且不直观。

因此,另一种方法是使用Jackson的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(); 
     } 
    } 
}