मैं GSON का उपयोग करके JSON को एक HashMap में कैसे बदल सकता हूं?


286

मैं JSON प्रारूप में डेटा लौटाने वाले सर्वर से डेटा का अनुरोध कर रहा हूं। अनुरोध करते समय JSON में एक HashMap कास्टिंग करना बिल्कुल भी मुश्किल नहीं था, लेकिन दूसरा तरीका थोड़ा मुश्किल लगता है। JSON प्रतिक्रिया इस तरह दिखती है:

{ 
    "header" : { 
        "alerts" : [ 
            {
                "AlertID" : "2",
                "TSExpires" : null,
                "Target" : "1",
                "Text" : "woot",
                "Type" : "1"
            },
            { 
                "AlertID" : "3",
                "TSExpires" : null,
                "Target" : "1",
                "Text" : "woot",
                "Type" : "1"
            }
        ],
        "session" : "0bc8d0835f93ac3ebbf11560b2c5be9a"
    },
    "result" : "4be26bc400d3c"
}

इस डेटा तक पहुंचने के लिए कौन सा रास्ता आसान होगा? मैं GSON मॉड्यूल का उपयोग कर रहा हूं।


23
Map<String,Object> result = new Gson().fromJson(json, Map.class);ग्सन 2.6.2 के साथ काम करता है।
फेरन मायलिनच

1
वापस कन्वर्ट करने के लिए कैसे? मेरा मतलब है मैप से लेकर जौन अर्रे तक।
K.Sopheak

जवाबों:


471

हेयर यू गो:

import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;

Type type = new TypeToken<Map<String, String>>(){}.getType();
Map<String, String> myMap = gson.fromJson("{'k1':'apple','k2':'orange'}", type);

6
एक अच्छा है, लेकिन मुझे TypeTokenइसका उपयोग करना पसंद नहीं है - यह अंदर की कास्टिंग को निहित करता है।
एलिकएल्ज़िन-किलाका

मानचित्र के लिए कास्टिंग <>, आपने मेरी हताशा को समाप्त कर दिया!
डेक्सटर

1
क्या वह वैध जसन उदाहरण में है?
इवान कायरुज

@ EvanKairuz नहीं, यह नहीं है। यह होना चाहिए{"k1":"apple","k2":"orange"}
वादिम कोटोव

क्या होगा अगर मुझे स्ट्रिंग बदलने की ज़रूरत है जो वास्तव में एक सरणी है
रवि यादव

111

यह कोड काम करता है:

Gson gson = new Gson(); 
String json = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
Map<String,Object> map = new HashMap<String,Object>();
map = (Map<String,Object>) gson.fromJson(json, map.getClass());

1
यह स्ट्रट्स को स्ट्रिंग्स में बदलने से पहले ही फ्लोट्स में बदल देगा, लेकिन यह JSON को तुलनात्मक उद्देश्यों के लिए मैप्स में बदलने का काम करेगा।
लाउलीउई

12
मेरे लिए बहुत अच्छा काम करता है, लेकिन मैंने नक्शा बदल दिया Map<String, Object>क्योंकि अगर जॉगिंग केवल तार नहीं है तो आपको एक त्रुटि मिलती है
मोशे शाहम

5
यह गलत धारणा देता है। पैरामीटर किए गए प्रकारों के लिए सही समाधान है TypeToken
सोथिरियोस डेलिमोनोलिस

यह सभी प्रकार के लिए एक सामान्य समाधान होगा, लेकिन थोड़ा असामान्य।
लियोन

76

मुझे पता है कि यह एक काफी पुराना सवाल है, लेकिन मैं जेन्सन को नेस्टेड जेनेरिक डीसिएरलाइज़ करने के लिए एक समाधान खोज रहा था Map<String, Object>, और कुछ भी नहीं मिला।

जिस तरह से मेरा yaml deserializer काम करता है, यह JSON ऑब्जेक्ट्स को Map<String, Object>तब परिभाषित करता है जब आप एक प्रकार निर्दिष्ट नहीं करते हैं, लेकिन gson ऐसा नहीं करता है। सौभाग्य से आप इसे कस्टम डेज़राइज़र के साथ पूरा कर सकते हैं।

मैं स्वाभाविक रूप से deserialize कुछ भी करने के लिए निम्न deserializer इस्तेमाल किया, दोषी JsonObjectको रों Map<String, Object>और JsonArrayकरने के लिए रों Object[]रों है, जहां सभी बच्चों इसी तरह deserialized कर रहे हैं।

private static class NaturalDeserializer implements JsonDeserializer<Object> {
  public Object deserialize(JsonElement json, Type typeOfT, 
      JsonDeserializationContext context) {
    if(json.isJsonNull()) return null;
    else if(json.isJsonPrimitive()) return handlePrimitive(json.getAsJsonPrimitive());
    else if(json.isJsonArray()) return handleArray(json.getAsJsonArray(), context);
    else return handleObject(json.getAsJsonObject(), context);
  }
  private Object handlePrimitive(JsonPrimitive json) {
    if(json.isBoolean())
      return json.getAsBoolean();
    else if(json.isString())
      return json.getAsString();
    else {
      BigDecimal bigDec = json.getAsBigDecimal();
      // Find out if it is an int type
      try {
        bigDec.toBigIntegerExact();
        try { return bigDec.intValueExact(); }
        catch(ArithmeticException e) {}
        return bigDec.longValue();
      } catch(ArithmeticException e) {}
      // Just return it as a double
      return bigDec.doubleValue();
    }
  }
  private Object handleArray(JsonArray json, JsonDeserializationContext context) {
    Object[] array = new Object[json.size()];
    for(int i = 0; i < array.length; i++)
      array[i] = context.deserialize(json.get(i), Object.class);
    return array;
  }
  private Object handleObject(JsonObject json, JsonDeserializationContext context) {
    Map<String, Object> map = new HashMap<String, Object>();
    for(Map.Entry<String, JsonElement> entry : json.entrySet())
      map.put(entry.getKey(), context.deserialize(entry.getValue(), Object.class));
    return map;
  }
}

handlePrimitiveविधि के अंदर की गड़बड़ी यह सुनिश्चित करने के लिए है कि आपको केवल एक डबल या एक इंटेगर या एक लॉन्ग प्राप्त हो, और संभवत: बेहतर हो, या कम से कम सरलीकृत हो सकता है यदि आप बिगडेकिमल प्राप्त करने के साथ ठीक हैं, जो मुझे लगता है कि डिफ़ॉल्ट है।

आप इस एडाप्टर को पंजीकृत कर सकते हैं जैसे:

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Object.class, new NaturalDeserializer());
Gson gson = gsonBuilder.create();

और फिर इसे कॉल करें:

Object natural = gson.fromJson(source, Object.class);

मुझे यकीन नहीं है कि यह गन्स में डिफ़ॉल्ट व्यवहार क्यों नहीं है, क्योंकि यह अधिकांश अन्य अर्ध-संरचित क्रमांकन पुस्तकालयों में है ...


1
... हालाँकि मुझे यकीन नहीं है कि अब मुझे वापस आने वाली वस्तुओं के साथ क्या करना है। उन्हें स्ट्रिंग के रूप में कास्ट करने के लिए प्रतीत नहीं हो सकता है, हालांकि मुझे पता है कि वे स्ट्रिंग्स हैं
मैट ज़ुकोव्स्की

1
अहा! चाल थी deserializer के बजाय recursively संदर्भ के बजाय कॉल। डिजाइन () कॉल।
मैट ज़ुकोवस्की

1
क्या आपके पास कुछ कोड मैट होगा? मैं डिसेरिज़ाइज़र पर बदलाव करने की कोशिश कर रहा हूँ, लेकिन मैं वास्तव में आपकी बात नहीं देख सकता हूँ
रोमेन पायल

5
अब डिफ़ॉल्ट रूप से गॉन के व्यवहार से प्रतीत होता है कि केविन डोलन अपने कोड स्निपेट में जा रहे हैं।
हाथीलेकराम

1
@SomeoneSomewhere यहां स्वीकृत उत्तर देखें stackoverflow.com/questions/14944419/gson-to-hashmap
MY

32

Google के Gson 2.7 के साथ (शायद पहले के संस्करण भी, लेकिन मैंने वर्तमान संस्करण 2.7 के साथ परीक्षण किया) यह उतना ही सरल है:

Map map = gson.fromJson(jsonString, Map.class);

जो एक Mapप्रकार का रिटर्न देता है com.google.gson.internal.LinkedTreeMapऔर नेस्टेड ऑब्जेक्ट्स, एरेज़ आदि पर पुनरावृत्ति करता है।

मैंने ओपी उदाहरण को ऐसे ही चलाया (बस सिंगल-कोट्स को हटा दिया गया और व्हॉट्सएप हटा दिया गया):

String jsonString = "{'header': {'alerts': [{'AlertID': '2', 'TSExpires': null, 'Target': '1', 'Text': 'woot', 'Type': '1'}, {'AlertID': '3', 'TSExpires': null, 'Target': '1', 'Text': 'woot', 'Type': '1'}], 'session': '0bc8d0835f93ac3ebbf11560b2c5be9a'}, 'result': '4be26bc400d3c'}";
Map map = gson.fromJson(jsonString, Map.class);
System.out.println(map.getClass().toString());
System.out.println(map);

और निम्न आउटपुट मिला:

class com.google.gson.internal.LinkedTreeMap
{header={alerts=[{AlertID=2, TSExpires=null, Target=1, Text=woot, Type=1}, {AlertID=3, TSExpires=null, Target=1, Text=woot, Type=1}], session=0bc8d0835f93ac3ebbf11560b2c5be9a}, result=4be26bc400d3c}

25

नए Gson lib के लिए अपडेट करें:
अब आप सीधे Json को मैप के लिए नेस्टेड कर सकते हैं, लेकिन आपको Json को Map<String, Object>टाइप करने के लिए पार्स करने की कोशिश करने के मामले में पता होना चाहिए : यह अपवाद को बढ़ाएगा। इसे ठीक करने के लिए, केवल परिणाम को LinkedTreeMapप्रकार के रूप में घोषित करें । नीचे उदाहरण:

String nestedJSON = "{"id":"1","message":"web_didload","content":{"success":1}};
Gson gson = new Gson();
LinkedTreeMap result = gson.fromJson(nestedJSON , LinkedTreeMap.class);

मैं कहाँ से LinkedTreeMap आयात करते हैं? मैं इसे Gson कोड में नहीं ढूँढ सकता।
हेल्पमैस्टैकऑवरफ्लो मैय्यलोइलोप

जैसा कि मुझे याद है, LinkedTreeMap को नए Gson lib में परिभाषित किया गया है। आप यहाँ देख सकते हैं: code.google.com/p/google-gson/source/browse/trunk/gson/src/main/…
Hoang Nguyen Huu

1
मेरे लिए यह भी साथ काम करता है Map<String,Object> result = gson.fromJson(json , Map.class);। गसन 2.6.2 का उपयोग करना।
फेरन मायलिनच

12

मेरा वही सवाल था और यहीं खत्म हुआ। मेरे पास एक अलग दृष्टिकोण था जो बहुत सरल लगता है (शायद नए संस्करण गेसन के?)।

    Gson gson = new Gson();
    Map jsonObject = (Map) gson.fromJson(data, Object.class);

निम्नलिखित json के साथ

{
  "map-00": {
    "array-00": [
      "entry-00",
      "entry-01"
     ],
     "value": "entry-02"
   }
}

निम्नलिखित

    Map map00 = (Map) jsonObject.get("map-00");
    List array00 = (List) map00.get("array-00");
    String value = (String) map00.get("value");
    for (int i = 0; i < array00.size(); i++) {
        System.out.println("map-00.array-00[" + i + "]= " + array00.get(i));
    }
    System.out.println("map-00.value = " + value);

आउटपुट

map-00.array-00[0]= entry-00
map-00.array-00[1]= entry-01
map-00.value = entry-02

जब आप अपने jsonObject को नेविगेट कर रहे हैं, तो आप इंस्टाफ़ॉइड का उपयोग करके गतिशील रूप से जांच कर सकते हैं। कुछ इस तरह

Map json = gson.fromJson(data, Object.class);
if(json.get("field") instanceof Map) {
  Map field = (Map)json.get("field");
} else if (json.get("field") instanceof List) {
  List field = (List)json.get("field");
} ...

यह मेरे लिए काम करता है, इसलिए यह आपके लिए काम करना चाहिए ;-)


6

नीचे 2.8 gson के बाद से समर्थित है

public static Type getMapType(Class keyType, Class valueType){
    return TypeToken.getParameterized(HashMap.class, keyType, valueType).getType();
}

public static  <K,V> HashMap<K,V> fromMap(String json, Class<K> keyType, Class<V> valueType){
    return gson.fromJson(json, getMapType(keyType,valueType));
}

3

यह कोशिश करो, यह काम करेगा। मैंने इसे हैशटेबल के लिए इस्तेमाल किया ।

public static Hashtable<Integer, KioskStatusResource> parseModifued(String json) {
    JsonObject object = (JsonObject) new com.google.gson.JsonParser().parse(json);
    Set<Map.Entry<String, JsonElement>> set = object.entrySet();
    Iterator<Map.Entry<String, JsonElement>> iterator = set.iterator();

    Hashtable<Integer, KioskStatusResource> map = new Hashtable<Integer, KioskStatusResource>();

    while (iterator.hasNext()) {
        Map.Entry<String, JsonElement> entry = iterator.next();

        Integer key = Integer.parseInt(entry.getKey());
        KioskStatusResource value = new Gson().fromJson(entry.getValue(), KioskStatusResource.class);

        if (value != null) {
            map.put(key, value);
        }

    }
    return map;
}

KioskStatusResource को अपनी कक्षा में और पूर्णांक को अपनी प्रमुख कक्षा में बदलें ।


इसके बाद मेरे लिए काम किया हैशशप ने एक लिंक्डट्रीपेज़ अपवाद को फेंक दिया।
newfivefour

2

यहाँ मैं उपयोग कर रहा हूँ:

public static HashMap<String, Object> parse(String json) {
    JsonObject object = (JsonObject) parser.parse(json);
    Set<Map.Entry<String, JsonElement>> set = object.entrySet();
    Iterator<Map.Entry<String, JsonElement>> iterator = set.iterator();
    HashMap<String, Object> map = new HashMap<String, Object>();
    while (iterator.hasNext()) {
        Map.Entry<String, JsonElement> entry = iterator.next();
        String key = entry.getKey();
        JsonElement value = entry.getValue();
        if (!value.isJsonPrimitive()) {
            map.put(key, parse(value.toString()));
        } else {
            map.put(key, value.getAsString());
        }
    }
    return map;
}

2

यहां एक-लाइनर है जो यह करेगा:

HashMap<String, Object> myMap =
   gson.fromJson(yourJson, new TypeToken<HashMap<String, Object>>(){}.getType());

हाँ, यह एक पंक्ति है, लेकिन ध्यान रखें कि new TypeToken<HashMap<String, Object>>(){}एक नई इनलाइन सब-क्लास बनाएगी, और सभी लिंटर कम से कम एक चेतावनी देंगे, मुझे लगता है
मार्टिन मेसर

1

मैंने कस्टम JsonDeSerializer के साथ इसी तरह की समस्या को दूर किया है। मैंने इसे थोड़ा सामान्य बनाने की कोशिश की लेकिन अभी भी पर्याप्त नहीं है। यह एक समाधान है, जो मेरी जरूरतों को पूरा करता है।

सबसे पहले आपको मानचित्र वस्तुओं के लिए एक नया JsonDeserializer लागू करने की आवश्यकता है।

public class MapDeserializer<T, U> implements JsonDeserializer<Map<T, U>>

और deserialize विधि इस तरह दिखाई देगी:

public Map<T, U> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {

        if (!json.isJsonObject()) {
            return null;
        }

        JsonObject jsonObject = json.getAsJsonObject();
        Set<Entry<String, JsonElement>> jsonEntrySet = jsonObject.entrySet();
        Map<T, U> deserializedMap = new HashMap<T, U>();

        for (Entry<java.lang.String, JsonElement> entry : jsonEntrySet) {
            try {
                U value = context.deserialize(entry.getValue(), getMyType());
                deserializedMap.put((T) entry.getKey(), value);
            } catch (Exception ex) {
                logger.info("Could not deserialize map.", ex);
            }
        }

        return deserializedMap;
    }

इस समाधान के साथ चुनाव, यह है कि मेरे मानचित्र की कुंजी हमेशा टाइप "स्ट्रिंग" है। हालाँकि कुछ चीजों का जाप करने से कोई इसे सामान्य बना सकता है। इसके अलावा, मुझे यह कहने की ज़रूरत है, कि मूल्य वर्ग को कंस्ट्रक्टर में पारित किया जाना चाहिए। इसलिए getMyType()मेरे कोड में विधि मानचित्र के मानों के प्रकार को लौटाती है, जो कि कंस्ट्रक्टर में पारित किया गया था।

आप इस पोस्ट का संदर्भ दे सकते हैं कि मैं Gson के लिए एक कस्टम JSON डेज़रलाइज़र कैसे लिखूं? कस्टम deserializers के बारे में अधिक जानने के लिए।


1

आप इसके बजाय इस वर्ग का उपयोग कर सकते हैं :) (यहां तक ​​कि सूचियों, नेस्टेड सूचियों और json को संभालता है)

public class Utility {

    public static Map<String, Object> jsonToMap(Object json) throws JSONException {

        if(json instanceof JSONObject)
            return _jsonToMap_((JSONObject)json) ;

        else if (json instanceof String)
        {
            JSONObject jsonObject = new JSONObject((String)json) ;
            return _jsonToMap_(jsonObject) ;
        }
        return null ;
    }


   private static Map<String, Object> _jsonToMap_(JSONObject json) throws JSONException {
        Map<String, Object> retMap = new HashMap<String, Object>();

        if(json != JSONObject.NULL) {
            retMap = toMap(json);
        }
        return retMap;
    }


    private static Map<String, Object> toMap(JSONObject object) throws JSONException {
        Map<String, Object> map = new HashMap<String, Object>();

        Iterator<String> keysItr = object.keys();
        while(keysItr.hasNext()) {
            String key = keysItr.next();
            Object value = object.get(key);

            if(value instanceof JSONArray) {
                value = toList((JSONArray) value);
            }

            else if(value instanceof JSONObject) {
                value = toMap((JSONObject) value);
            }
            map.put(key, value);
        }
        return map;
    }


    public static List<Object> toList(JSONArray array) throws JSONException {
        List<Object> list = new ArrayList<Object>();
        for(int i = 0; i < array.length(); i++) {
            Object value = array.get(i);
            if(value instanceof JSONArray) {
                value = toList((JSONArray) value);
            }

            else if(value instanceof JSONObject) {
                value = toMap((JSONObject) value);
            }
            list.add(value);
        }
        return list;
    }
}

अपने JSON स्ट्रिंग को हैशमैप में बदलने के लिए इसका उपयोग करें:

HashMap<String, Object> hashMap = new HashMap<>(Utility.jsonToMap(response)) ;

0

यह केविन डोलन के जवाब के पूर्ण उत्तर की तुलना में अधिक है, लेकिन मुझे नंबर से टाइप निकालने में परेशानी हो रही थी। यह मेरा समाधान है:

private Object handlePrimitive(JsonPrimitive json) {
  if(json.isBoolean()) {
    return json.getAsBoolean();
  } else if(json.isString())
    return json.getAsString();
  }

  Number num = element.getAsNumber();

  if(num instanceof Integer){
    map.put(fieldName, num.intValue());
  } else if(num instanceof Long){
    map.put(fieldName, num.longValue());
  } else if(num instanceof Float){
    map.put(fieldName, num.floatValue());
  } else {    // Double
     map.put(fieldName, num.doubleValue());
  }
}

-1
 HashMap<String, String> jsonToMap(String JsonDetectionString) throws JSONException {

    HashMap<String, String> map = new HashMap<String, String>();
    Gson gson = new Gson();

    map = (HashMap<String, String>) gson.fromJson(JsonDetectionString, map.getClass());

    return map;

}

-3

JSONObject आमतौर पर HashMapडेटा को स्टोर करने के लिए आंतरिक रूप से उपयोग करता है । तो, आप इसे अपने कोड में मैप के रूप में उपयोग कर सकते हैं।

उदाहरण,

JSONObject obj = JSONObject.fromObject(strRepresentation);
Iterator i = obj.entrySet().iterator();
while (i.hasNext()) {
   Map.Entry e = (Map.Entry)i.next();
   System.out.println("Key: " + e.getKey());
   System.out.println("Value: " + e.getValue());
}

12
यह json-lib से है, न कि gson!
अम्मार

-3

मैंने इस कोड का उपयोग किया है:

Gson gson = new Gson();
HashMap<String, Object> fields = gson.fromJson(json, HashMap.class);

यह मुझे अनियंत्रित रूपांतरण चेतावनी देता है।
रेखा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.