2012-07-31 19 views
35
{ 
    vendors: [ 
    { 
     vendor: { 
     id: 367, 
     name: "Kuhn-Pollich", 
     company_id: 1, 
     } 
    }, 
    { 
     vendor: { 
     id: 374, 
     name: "Sawayn-Hermann", 
     company_id: 1, 
     } 
    }] 
} 

मैं एक वेंडर उद्देश्य यह है कि ठीक से एक भी "विक्रेता" json से deserialized किया जा सकता है, लेकिन मैं एक Vendor[] में इस deserialize करने के लिए, मैं सिर्फ यह पता लगाने नहीं कर सकते कि जैक्सन सहयोग करना चाहते हैं। कोई सुझाव?जैक्सन - नेस्टेड JSON को कैसे संसाधित (deserialize)?

+3

यह अमान्य JSON है। 'विक्रेताओं 'के पास एक सरणी मानी जाती है, जिसमें एक ही वस्तु होती है, और एकल ऑब्जेक्ट में' विक्रेता 'संपत्ति होती है, जिसके बाद एक नंगे शीर्ष-स्तरीय ओपेक्ट होता है। यानी दूसरी 'विक्रेता' ऑब्जेक्ट में सरणी में मौजूद एकल ऑब्जेक्ट में कोई संबंधित प्रॉपर्टी नहीं है। इसके अलावा, संपत्ति के नाम तार नहीं हैं, उन्हें JSON में उद्धृत करने की आवश्यकता है। मुझे लगता है कि आपने JSON को गलत में टाइप किया है? एक अच्छा जवाब यह जानने पर निर्भर करेगा कि आप किस प्रकार के JSOn वास्तव में काम कर रहे हैं। – pb2q

+0

क्षमा करें, मुझे JSON को सही करने दें - अब –

+0

तय किया जाना चाहिए आप एक विक्रेता श्रेणी नहीं कर सकते हैं (या नहीं चाहते) जिसमें एक सूची है? – hertzsprung

उत्तर

23

आपका डेटा समस्याग्रस्त है कि आपके भीतर आपके रैपर ऑब्जेक्ट्स हैं। संभवतः आपके Vendor ऑब्जेक्ट को id, name, company_id को संभालने के लिए डिज़ाइन किया गया है, लेकिन उनमें से प्रत्येक ऑब्जेक्ट को एक ऑब्जेक्ट में एक ही संपत्ति vendor के साथ लपेटा गया है।

मुझे लगता है कि आप जैक्सन Data Binding मॉडल का उपयोग कर रहे हैं।

यदि ऐसा है तो वहाँ दो बातों पर विचार करने के लिए कर रहे हैं:

पहले एक विशेष जैक्सन config संपत्ति का उपयोग कर रहा है। जैक्सन - 1.9 से मेरा मानना ​​है कि यदि आप जैक्सन के पुराने संस्करण का उपयोग कर रहे हैं तो यह उपलब्ध नहीं हो सकता है - UNWRAP_ROOT_VALUE प्रदान करता है। यह उन मामलों के लिए डिज़ाइन किया गया है जहां आपके परिणाम शीर्ष-स्तरीय सिंगल-प्रॉपर्टी ऑब्जेक्ट में लपेटे गए हैं जिन्हें आप त्यागना चाहते हैं। आवरण वस्तुओं का उपयोग कर रहा

objectMapper.configure(SerializationConfig.Feature.UNWRAP_ROOT_VALUE, true); 

दूसरा:

तो, के साथ चारों ओर खेलते हैं। बाहरी रैपर ऑब्जेक्ट को छोड़ने के बाद भी आपको एक ही-संपत्ति ऑब्जेक्ट में लिपटे Vendor ऑब्जेक्ट्स की समस्या है। इस के आसपास पाने के लिए एक आवरण का उपयोग करें:

class VendorWrapper 
{ 
    Vendor vendor; 

    // gettors, settors for vendor if you need them 
} 

इसी तरह, बजाय UNWRAP_ROOT_VALUES का उपयोग कर के, आप भी एक आवरण वर्ग बाहरी वस्तु को संभालने के लिए निर्धारित कर सकते हैं। यह मानते हुए कि आपके पास सही Vendor, VendorWrapper वस्तु, आप को परिभाषित कर सकते हैं:

class VendorsWrapper 
{ 
    List<VendorWrapper> vendors = new ArrayList<VendorWrapper>(); 

    // gettors, settors for vendors if you need them 
} 

// in your deserialization code: 
ObjectMapper mapper = new ObjectMapper(); 
JsonNode rootNode = mapper.readValue(jsonInput, VendorsWrapper.class); 

VendorsWrapper के लिए वस्तु पेड़ आपके JSON के अनुरूप है:

VendorsWrapper: 
    vendors: 
    [ 
     VendorWrapper 
      vendor: Vendor, 
     VendorWrapper: 
      vendor: Vendor, 
     ... 
    ] 

अंत में, आप जैक्सन Tree Model उपयोग कर सकते हैं इस पार्स करने के लिए

mapper.readValue(node.get("vendor").getTextValue(), Vendor.class); 
: JsonNodes, बाहरी नोड को त्यागकर, और ArrayNode में प्रत्येक JsonNode के लिए, बुला में

जिसके परिणामस्वरूप कम कोड हो सकता है, लेकिन यह दो रैपर का उपयोग करने से कम बेकार लगता है।

+0

धन्यवाद, इस तरह मैं इसे कर रहा था, मुझे उम्मीद थी कि एक बेहतर तरीका था। मैं इसे सही के रूप में चिह्नित करूंगा। –

+0

मैं UNWRAP_ROOT_VALUES जैसे कुछ का उपयोग करके समाधान देखना चाहता हूं, केवल 1 स्तर गहरा है, लेकिन मुझे नहीं लगता कि यह संभव है। पाठ्यक्रम का एक और विकल्प एक कस्टम deserializer का उपयोग करना है, और केवल अपनी वास्तविक वस्तुओं को देखने के लिए हुक जोड़ें और बाकी सब कुछ छोड़ दें, या जैक्सन _Tree मॉडल_ दृष्टिकोण का उपयोग करने के लिए, शीर्ष-स्तर 'जेसन नोड' को फेंक दें, और जेसननोड्स को लें जो आपके विक्रेताओं को लपेटते हैं, 'getTextValue' पर कॉल करें, और _that_ को' mapper.readValue 'पर पास करें। जैक्सन वास्तव में आपको विकल्पों का एक सरफ़ान देता है। – pb2q

28

यहां एक मोटा लेकिन अधिक घोषणात्मक समाधान है। मैं इसे एक ही टिप्पणी में नहीं ले पाया, लेकिन ऐसा लगता है कि यह अच्छी तरह से काम करता है। बड़े डेटा सेट पर प्रदर्शन के बारे में भी सुनिश्चित नहीं है।

को देखते हुए इस JSON:

{ 
    "list": [ 
     { 
      "wrapper": { 
       "name": "Jack" 
      } 
     }, 
     { 
      "wrapper": { 
       "name": "Jane" 
      } 
     } 
    ] 
} 

और ये मॉडल वस्तुओं:

public class RootObject { 
    @JsonProperty("list") 
    @JsonDeserialize(contentUsing = SkipWrapperObjectDeserializer.class) 
    @SkipWrapperObject("wrapper") 
    public InnerObject[] innerObjects; 
} 

और

public class InnerObject { 
    @JsonProperty("name") 
    public String name; 
} 

कहाँ जैक्सन वूडू की तरह कार्यान्वित किया जाता है:

@Retention(RetentionPolicy.RUNTIME) 
@JacksonAnnotation 
public @interface SkipWrapperObject { 
    String value(); 
} 

और

public class SkipWrapperObjectDeserializer extends JsonDeserializer<Object> implements 
     ContextualDeserializer { 
    private Class<?> wrappedType; 
    private String wrapperKey; 

    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, 
      BeanProperty property) throws JsonMappingException { 
     SkipWrapperObject skipWrapperObject = property 
       .getAnnotation(SkipWrapperObject.class); 
     wrapperKey = skipWrapperObject.value(); 
     JavaType collectionType = property.getType(); 
     JavaType collectedType = collectionType.containedType(0); 
     wrappedType = collectedType.getRawClass(); 
     return this; 
    } 

    @Override 
    public Object deserialize(JsonParser parser, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException { 
     ObjectMapper mapper = new ObjectMapper(); 
     ObjectNode objectNode = mapper.readTree(parser); 
     JsonNode wrapped = objectNode.get(wrapperKey); 
     Object mapped = mapIntoObject(wrapped); 
     return mapped; 
    } 

    private Object mapIntoObject(JsonNode node) throws IOException, 
      JsonProcessingException { 
     JsonParser parser = node.traverse(); 
     ObjectMapper mapper = new ObjectMapper(); 
     return mapper.readValue(parser, wrappedType); 
    } 
} 

इस आशा किसी के लिए उपयोगी है!

+0

'mapIntoObject (JsonNode)' के लिए +1 ... इसलिए यदि आप 'जेसननोड' के साथ 'readValue' का उपयोग करना चाहते हैं तो बस अपने' ट्रैवर्स() ' – rakslice

+2

को अच्छी तरह से काम करता है: एक मामूली सरलीकरण जो मैं सुझाता हूं वह 'ऑब्जेक्टमैपर' है। कनवर्ट करें() ', जिसका उपयोग 'mapIntoObject' में 3 लाइनों को प्रतिस्थापित करने के लिए किया जा सकता है:' वापसी mapper.convertValue (नोड, लपेटा टाइप); ' – StaxMan

+1

@ पैट्रिक, मैंने इस उदाहरण कोड को चलाने का प्रयास किया। पर SkipWrapperObjectDeserializer में एनपीई प्राप्त करना wrappedType = collectType.getRawClass(); CreateContextual() विधि में । क्या आप इसे ठीक करने में मेरी मदद कर सकते हैं। धन्यवाद। –

7

@Patrick मैं अपने समाधान थोड़ा

@Override 
public Object deserialize(JsonParser jp, DeserializationContext ctxt) 
     throws IOException, JsonProcessingException {   
    ObjectNode objectNode = jp.readValueAsTree(); 
    JsonNode wrapped = objectNode.get(wrapperKey); 
    JsonParser parser = node.traverse(); 
    parser.setCodec(jp.getCodec()); 
    Vendor mapped = parser.readValueAs(Vendor.class); 
    return mapped; 
} 

में सुधार होगा यह तेजी से काम करता है :)

संबंधित मुद्दे