2017-05-06 15 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(); 
     } 
    } 
} 
関連する問題