2017-05-06 6 views
0

다음과 같이 샘플 JSON이 있습니다. 이 객체를 UI에 표준 인 다른 JSON 형식 (다른 공급 업체와 다른 주문을 받고 공통 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으로 파싱해야하고 트리 모델로 작업하고 있고 잭슨의 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(); 
     } 
    } 
}