Java 如何使用 Gson 将 JSON 转换为 HashMap?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2779251/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 12:45:46  来源:igfitidea点击:

How can I convert JSON to a HashMap using Gson?

javajsondictionaryhashmapgson

提问by Mridang Agarwalla

I'm requesting data from a server which returns data in the JSON format. Casting a HashMap into JSON when making the request wasn't hard at all but the other way seems to be a little tricky. The JSON response looks like this:

我正在从以 JSON 格式返回数据的服务器请求数据。在发出请求时将 HashMap 转换为 JSON 一点也不难,但另一种方式似乎有点棘手。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"
}

What way would be easiest to access this data? I'm using the GSON module.

哪种方式最容易访问这些数据?我正在使用 GSON 模块。

采纳答案by cherit

Here you go:

干得好:

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);

回答by Phanindra

JSONObject typically uses HashMapinternally to store the data. So, you can use it as Map in your code.

JSONObject 通常在HashMap内部使用来存储数据。因此,您可以在代码中将其用作 Map。

Example,

例子,

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());
}

回答by Kevin Dolan

I know this is a fairly old question, but I was searching for a solution to generically deserialize nested JSON to a Map<String, Object>, and found nothing.

我知道这是一个相当古老的问题,但我一直在寻找一种解决方案,将嵌套的 JSON 反序列化为 a Map<String, Object>,但一无所获。

The way my yaml deserializer works, it defaults JSON objects to Map<String, Object>when you don't specify a type, but gson doesn't seem to do this. Luckily you can accomplish it with a custom deserializer.

我的 yaml 反序列化器的工作方式是,Map<String, Object>当您未指定类型时,它会将 JSON 对象默认为,但 gson 似乎没有这样做。幸运的是,您可以使用自定义解串器来完成它。

I used the following deserializer to naturally deserialize anything, defaulting JsonObjects to Map<String, Object>and JsonArrays to Object[]s, where all the children are similarly deserialized.

我使用以下反序列化器自然地反序列化任何东西,默认JsonObjectsMap<String, Object>JsonArrays 到Object[]s,其中所有子级都类似地反序列化。

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;
  }
}

The messiness inside the handlePrimitivemethod is for making sure you only ever get a Double or an Integer or a Long, and probably could be better, or at least simplified if you're okay with getting BigDecimals, which I believe is the default.

handlePrimitive方法内部的混乱是为了确保您只获得 Double 或 Integer 或 Long,并且可能会更好,或者如果您可以获取 BigDecimals,则至少可以简化,我认为这是默认设置。

You can register this adapter like:

您可以像这样注册这个适配器:

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

And then call it like:

然后像这样调用它:

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

I'm not sure why this is not the default behavior in gson, since it is in most other semi-structured serialization libraries...

我不确定为什么这不是 gson 中的默认行为,因为它在大多数其他半结构化序列化库中...

回答by OZG

Here is what I have been using:

这是我一直在使用的:

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;
}

回答by Angel

This code works:

此代码有效:

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());

回答by R4U

Try this, it will worked. I used it for Hashtable.

试试这个,它会起作用。我将它用于Hashtable

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;
}

Replace KioskStatusResourceto your class and Integerto your key class.

KioskStatusResource替换为您的类,将Integer替换为您的关键类。

回答by nikkatsa

I have overcome a similar problem with a Custom JsonDeSerializer. I tried to make it a bit generic but still not enough. It is a solution though that fits my needs.

我已经用自定义 JsonDeSerializer 克服了类似的问题。我试图让它有点通用,但仍然不够。虽然这是一个满足我需求的解决方案。

First of all you need to implement a new JsonDeserializer for Map objects.

首先,您需要为 Map 对象实现一个新的 JsonDeserializer。

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

And the deserialize method will look similar to this:

反序列化方法看起来类似于:

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;
    }

The con with this solution, is that my Map's key is always of Type "String". However by chaning some things someone can make it generic. In addition, i need to say, that the value's class should be passed in the constructor. So the method getMyType()in my code returns the type of the Map's values, which was passed in the constructor.

这个解决方案的缺点是我的 Map 的键总是类型为“String”。然而,通过改变一些东西,有人可以使它成为通用的。另外,我需要说,值的类应该在构造函数中传递。所以getMyType()我的代码中的方法返回 Map 值的类型,它是在构造函数中传递的。

You can reference this post How do I write a custom JSON deserializer for Gson?in order to learn more about custom deserializers.

您可以参考这篇文章如何为 Gson 编写自定义 JSON 反序列化器?以了解有关自定义解串器的更多信息。

回答by Hoang Nguyen Huu

Update for new Gson lib:
You now can parse nested Json to Map directly, but you should be aware in case you try to parse Json to Map<String, Object>type: it will raise exception. To fix this, just declare the result as LinkedTreeMaptype. Example below:

更新新的 Gson 库:
您现在可以直接将嵌套的 Json 解析为 Map,但您应该注意,如果您尝试解析 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);

回答by krico

I had the exact same question and ended up here. I had a different approach that seems much simpler (maybe newer versions of gson?).

我有完全相同的问题,最后到了这里。我有一个看起来更简单的不同方法(也许是 gson 的新版本?)。

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

with the following json

使用以下 json

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

The following

下列

    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);

outputs

产出

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

You could dynamically check using instanceof when navigating your jsonObject. Something like

您可以在导航 jsonObject 时使用 instanceof 动态检查。就像是

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");
} ...

It works for me, so it must work for you ;-)

它对我有用,所以它一定对你有用;-)

回答by mortalis

I used this code:

我使用了这个代码:

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