2012-08-17 17 views
13

deserializing जबकि रूट तत्व छोड़ें रूट JS तत्व को छोड़ने के लिए निम्नलिखित JSON को कैसे deserialize और इस JSON के आंतरिक भाग को पार्स करना चाहिए। मैं अतिरिक्त, तृतीय वर्ग Root बनाने से बचना चाहता हूं, जिसमें केवल MapWrapper फ़ील्ड शामिल होगा।जेसन

{ 
    "root": { 
     "language": "en", 
     "map": { 
      "k1": { 
       "name": "n1", 
      }, 
      "k2": { 
       "name": "n2", 
      } 
     } 
    } 
} 

तो मैं केवल इन दो वर्गों करना चाहते हैं:

class MapWrapper { 
    private String language; 
    private Map<String, MyMapEntry> map; 
} 

class MyMapEntry { 
    String name; 
} 

उत्तर

10

आप इसके लिए GSON लाइब्रेरी का उपयोग कर सकते हैं।

नीचे कोड आपकी समस्या का समाधान करेगा।

public class ConvertJsonToObject { 

    private static Gson gson = new GsonBuilder().create(); 

    public static final <T> T getFromJSON(String json, Class<T> clazz) { 
     return gson.fromJson(json, clazz); 
    } 

    public static final <T> String toJSON(T clazz) { 
     return gson.toJson(clazz); 
    } 
} 

String json; // your jsonString 
Map<String,Object> r = ConvertJsonToObject.getFromJSON(json,Map.class); 
String innerJson = ConvertJsonToObject.toJson(r.get("root")); 
MapWrapper _r = ConvertJsonToObject.getFromJSON(innerJson,MapWrapper.class); 
+0

साफ समाधान। +1 –

+1

यह कोड दो बार json parses। क्या इससे बचना संभव है? –

+0

हाँ कस्टम JsonDeserializer लिखकर और इसे GSON में पंजीकृत करके ऐसा करना संभव है। – Byter

0

आप इसे एक Map<String, MapWrapper> में deserialize सकता है।

+0

आप डेटा कैसे deserializing कर रहे हैं (या योजना के लिए):

इटरेटर विधि की तरह दिखता है? (कोई विशेष ढांचा?) –

2

यह एक पास में ऐसा करने के लिए इष्टतम कोड है।

MapWrapper वर्ग

public class MapWrapper { 
    private String language; 
    private Map<String, MyMapEntry> map; 

    public MapWrapper(String language, Map<String, MyMapEntry> map) { 
     this.language = language; 
     this.map = map; 
    } 
} 

MyMapEntry वर्ग

public class MyMapEntry { 

    String name; 

    public MyMapEntry(String name) { 
     this.name = name; 
    } 
} 

कस्टम deserializer

public class MyDeserialiser implements JsonDeserializer<MapWrapper> 
{ 

    @Override 
    public MapWrapper deserialize(JsonElement json, Type typeOfT, 
     JsonDeserializationContext ctx) throws JsonParseException { 

     JsonObject _global = json.getAsJsonObject(); 
     _global = _global.get("root").getAsJsonObject(); 

     JsonPrimitive lang = (JsonPrimitive) _global.get("language"); 
     JsonElement map = _global.get("map"); 
     Map<String, MyMapEntry> inMap = new LinkedHashMap<String, MyMapEntry>(); 
     for (Entry<String, JsonElement> entry : map.getAsJsonObject() 
       .entrySet()) { 
      MyMapEntry _m = new MyMapEntry(entry.getValue().toString()); 
      inMap.put(entry.getKey(), _m); 
     } 
     return new MapWrapper(lang.getAsString(), inMap); 
    } 
} 

GSON

साथ
new GsonBuilder().registerTypeAdapter(MapWrapper.class,new MyDeserialiser()).create() 
यह रजिस्टर इस JSON के लिए मूल तत्व के बिना JSON का उपयोग कर से/

public class Authorization { 
    private String username; 
    private String password; 

    public String getUsername() { 
     return username; 
    } 

    public void setUsername(String username) { 
     this.username = username; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    // Add a container for the root element 
    public static class Container { 
     public Authorization authorization; 
    } 
} 

Convert

{"authorization":{"username":"userabc", "password":"passabc"}} 

डीटीओ:

अब कोड निम्नलिखित

String json; // your jsonString 
MapWrapper result = ConvertJsonToObject.getFromJSON(json,MapWrapper.class); 
+0

इससे मुझे अतिरिक्त वर्ग बना दिया जाता है, जो भिखारी से समस्या थी। ऐसा करने से, 'मैपरवापर' प्रकार के एक फ़ील्ड के साथ 'रैपर' वर्ग बनाने के लिए बेहतर कहा जाता है। –

+0

@Mathew वास्तव में – Byter

+0

रैपर के बिना रैपर वर्ग की कोई ज़रूरत नहीं है, यह शून्य ऑब्जेक्ट बनाता है, क्योंकि 'ctx.deserialize'' MapWrapper' ऑब्जेक्ट –

2

निम्नलिखित JSON पर विचार के साथ deserialise निम्नलिखित विधियां (आप या तो इसे डीटीओ या कुछ अन्य सहायता कक्षा में रख सकते हैं)

public String toJson(Authorization authorization) { 
    Gson gson = new Gson(); 
    Authorization.Container container = new Authorization.Container(); 
    container.authorization = authorization; 
    return gson.toJson(container); 
} 

public Authorization fromJson(String json) { 
    Gson gson = new Gson(); 
    Authorization.Container container = gson.fromJson(json, Authorization.Container.class); 
    return container.authorization; 
} 
+0

अच्छा समाधान मुझे wrt – Riskhan

0

गुस्ताव कार्लसन के विचार से प्रेरित मैंने इसे ठोस नमूने में विस्तारित करने का निर्णय लिया। यहां एक जूनिट टेस्ट है जो इस JSON को मानचित्र के रूप में पार्स करने का परीक्षण करता है।

public static class MapWrapper { 
    private String language; 
    private Map<String, MyMapEntry> map; 
} 

public static class MyMapEntry { 
    String name; 
} 

@Test 
public void testParsing() { 
    String json = "{\n" + 
      " \"root\": {\n" + 
      "  \"language\": \"en\",\n" + 
      "  \"map\": {\n" + 
      "   \"k1\": {\n" + 
      "    \"name\": \"n1\"\n" + 
      "   },\n" + 
      "   \"k2\": {\n" + 
      "    \"name\": \"n2\"\n" + 
      "   }\n" + 
      "  }\n" + 
      " }\n" + 
      "}"; 
    Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); 
    Type type = new TypeToken<Map<String, MapWrapper>>(){}.getType(); 
    Map<String, MapWrapper> parsed = gson.fromJson(json, type); 
    MapWrapper mapWrapper = parsed.get("root"); 
    Assert.assertEquals("en", mapWrapper.language); 
    Assert.assertEquals("n2", mapWrapper.map.get("k2").name); 
} 
2

मेरा उत्तर इस पार्टी के लिए देर हो चुकी है।

एक बार जब हम जेसन को पार्स करते हैं, तो कंटेनर हमेशा जेसन एलिमेंट के जेसनऑब्जेक्ट सबक्लास बनने जा रहा है। इस प्रकार, अगर हम इसे छोड़ना चाहते हैं, तो हमें इसे अपने उप-वर्ग में डालने और हमारे आंतरिक वर्ग को पकड़ने वाले क्षेत्र को पकड़ने की जरूरत है।

String response = ....; 

    Gson gson = new Gson(); 

    JsonParser p = new JsonParser(); 
    JsonElement jsonContainer = p.parse(response); 
    JsonElement jsonQuery = ((JsonObject) jsonContainer).get("query"); 

    MyQuery query = gson.fromJson(jsonQuery, MyQuery.class); 

नोट: JSONObject और JSONObject विभिन्न वर्गों (com.google.Json आयात का उपयोग करें) कर रहे हैं।

आप इस उत्तर को अधिक सामान्यीकृत कर सकते हैं कि आपको आंतरिक कक्षा का नाम जानने की आवश्यकता नहीं होगी।आप कंटेनर ऑब्जेक्ट का केवल एकमात्र क्षेत्र प्राप्त करके ऐसा करेंगे। हालांकि, मुझे इटेटरेटर शुरू करने के अलावा ऐसा करने का कोई तरीका नहीं दिखता है, मुझे कोई वैल्यू (एट इंडेक्स) विधि नहीं मिल सकती है, और मुझे लगता है कि एक इटरेटर शुरू करना शायद नाम से फ़ील्ड को देखकर कम कुशल है (लेकिन हो सकता है गलत)।

JsonElement jsonQuery = ((JsonObject) jsonContainer).entrySet().iterator() 
          .next().getValue();