2010-09-02 26 views
32

में एक अमूर्त वर्ग को Deserializing मेरे पास जेएसओएन प्रारूप में एक पेड़ वस्तु है मैं जीसन के साथ deserialize करने की कोशिश कर रहा हूँ। प्रत्येक नोड में ऑब्जेक्ट प्रकार नोड के फ़ील्ड के रूप में इसके बच्चे नोड्स होते हैं। नोड एक इंटरफेस है, जिसमें कई ठोस वर्ग कार्यान्वयन हैं। Deserialization प्रक्रिया के दौरान, मैं जीसन से कैसे संवाद कर सकता हूं जो नोड को deserializing लागू करने के लिए ठोस वर्ग, अगर मैं एक prei पता नहीं है जो नोड के प्रकार से संबंधित है? प्रत्येक नोड में सदस्य निर्दिष्ट क्षेत्र होता है। जब वस्तु क्रमबद्ध रूप में है, तो फ़ील्ड तक पहुंचने का कोई तरीका है, और किसी भी तरह से जीसन को टाइप करें?जीसन

धन्यवाद!

+0

करने के लिए [http://stackoverflow.com/a/22081826/3315914](http://stackoverflow.com/a/22081826/3315914) – rpax

उत्तर

40

मैं Node रों के लिए एक कस्टम JsonDeserializer जोड़ने का सुझाव चाहते हैं:

Gson gson = new GsonBuilder() 
    .registerTypeAdapter(Node.class, new NodeDeserializer()) 
    .create(); 

आप JsonElement deserializer की विधि में नोड का प्रतिनिधित्व करने का उपयोग एक JsonObject है कि परिवर्तित, और क्षेत्र को पुनः प्राप्त करने में सक्षम हो जाएगा कि प्रकार निर्दिष्ट करता है। इसके बाद आप उस पर आधारित Node के सही प्रकार का उदाहरण बना सकते हैं।

+0

कि पूरी तरह से काम किया है एक नजर डालें। धन्यवाद! – user437480

+0

@ eng-carlin यह अपरिवर्तनीय है और अगर यह आपके लिए काम करता है तो एक जवाब स्वीकार करें, इसलिए यदि आप ऐसा कर सकते हैं तो मैं इसकी सराहना करता हूं। – ColinD

+0

हरे रंग की चेक मार्क पर क्लिक किया गया है। मैं आपको उखाड़ फेंक दूंगा, लेकिन मेरी प्रतिष्ठा काफी अधिक नहीं है :( – user437480

22

आपको JSONSerializer और JSONDeserializer दोनों को पंजीकृत करने की आवश्यकता होगी। इसके अलावा आप अपने सभी इंटरफेस के लिए एक सामान्य एडाप्टर को निम्न तरीके से कार्यान्वित कर सकते हैं:

  • सीरियलाइजेशन के दौरान: वास्तविक इम्प्लाइट क्लास प्रकार की मेटा-जानकारी जोड़ें।
  • अक्रमांकन के दौरान: कि मेटा जानकारी प्राप्त करें और उस वर्ग

की JSONDeserailize फोन यहाँ कार्यान्वयन कि मैं खुद के लिए इस्तेमाल किया और ठीक काम करता है है।

public class PropertyBasedInterfaceMarshal implements 
     JsonSerializer<Object>, JsonDeserializer<Object> { 

    private static final String CLASS_META_KEY = "CLASS_META_KEY"; 

    @Override 
    public Object deserialize(JsonElement jsonElement, Type type, 
      JsonDeserializationContext jsonDeserializationContext) 
      throws JsonParseException { 
     JsonObject jsonObj = jsonElement.getAsJsonObject(); 
     String className = jsonObj.get(CLASS_META_KEY).getAsString(); 
     try { 
      Class<?> clz = Class.forName(className); 
      return jsonDeserializationContext.deserialize(jsonElement, clz); 
     } catch (ClassNotFoundException e) { 
      throw new JsonParseException(e); 
     } 
    } 

    @Override 
    public JsonElement serialize(Object object, Type type, 
      JsonSerializationContext jsonSerializationContext) { 
     JsonElement jsonEle = jsonSerializationContext.serialize(object, object.getClass()); 
     jsonEle.getAsJsonObject().addProperty(CLASS_META_KEY, 
       object.getClass().getCanonicalName()); 
     return jsonEle; 
    } 

} 

तो आप के रूप में जहाँ तक मुझे इस बता अधिक विशेष रूप से गैर-संग्रह प्रकार के लिए काम नहीं करता है, या कर सकते हैं के रूप में

Gson gson = new GsonBuilder() 
     .registerTypeAdapter(IInterfaceOne.class, 
       new PropertyBasedInterfaceMarshal()) 
     .registerTypeAdapter(IInterfaceTwo.class, 
       new PropertyBasedInterfaceMarshal()).create(); 
+0

IInterfaceOne.class और IInterfaceTwo.class –

+0

द्वारा आपका क्या मतलब है प्रदान करने के लिए धन्यवाद इस समस्या के लिए सबसे सुरुचिपूर्ण/पुन: प्रयोज्य समाधान। मैं '_class' का उपयोग' CLASS_META_KEY' के रूप में करता हूं जैसे कि mongodb करता है। – bekce

1

इस प्रकार अपने सभी इंटरफेस के लिए इस एडाप्टर रजिस्टर कर सकता है, स्थितियों में, जहां कंक्रीट प्रकार का उपयोग क्रमबद्ध करने के लिए किया जाता है, और इंटरफ़ेस प्रकार का उपयोग deserialize करने के लिए किया जाता है। यही है, यदि आपके पास एक इंटरफ़ेस को कार्यान्वित करने वाला एक सरल वर्ग है और आप कंक्रीट क्लास को क्रमबद्ध करते हैं, तो deserialize करने के लिए इंटरफ़ेस निर्दिष्ट करें, आप एक अप्राप्य स्थिति में समाप्त हो जाएंगे।

उपर्युक्त उदाहरण में प्रकार एडाप्टर इंटरफ़ेस के खिलाफ पंजीकृत है, लेकिन जब आप कंक्रीट क्लास का उपयोग करके क्रमबद्ध करते हैं तो इसका उपयोग नहीं किया जाएगा, जिसका अर्थ है कि CLASS_META_KEY डेटा कभी भी सेट नहीं होगा।

यदि आप एडैप्टर को पदानुक्रमित एडाप्टर के रूप में निर्दिष्ट करते हैं (इस प्रकार जीसन को पदानुक्रम में सभी प्रकार के लिए इसका उपयोग करने के लिए कहता है), तो आप एक अनंत लूप में समाप्त हो जाएंगे क्योंकि सीरिएलाइज़र केवल कॉलिंग करेगा।

कोई भी जानता है कि इंटरफ़ेस के ठोस कार्यान्वयन से क्रमबद्ध कैसे करें, फिर केवल इंटरफ़ेस और इंस्टेंस क्रिएटर का उपयोग करके deserialize करें?

डिफ़ॉल्ट रूप से ऐसा लगता है कि जीसन ठोस उदाहरण बनायेगा, लेकिन यह इसके फ़ील्ड सेट नहीं करता है।

मुद्दा यहां लॉग होता है:

http://code.google.com/p/google-gson/issues/detail?id=411&q=interface

0

आपके पास गूगल Gson से TypeToken वर्ग का उपयोग करने के। आप निश्चित रूप से की आवश्यकता होगी यह काम करता है

Type fooType = new TypeToken<Foo<Bar>>() {}.getType(); 

gson.toJson (foo, fooType) बनाने के लिए एक सामान्य वर्ग टी है;

gson.fromJson(json, fooType); 
संबंधित मुद्दे