我从一个返回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"
}

什么方法最容易访问这些数据?我正在使用GSON模块。


当前回答

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

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

我使用下面的反序列化器来自然地反序列化任何东西,默认的JsonObjects到Map<String,对象>和JsonArrays到对象[]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;
  }
}

handlePrimitive方法内部的混乱是为了确保您只获得Double或Integer或Long,可能会更好,或者至少可以简化,如果您愿意获得bigdecimal,我相信这是默认的。

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

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

然后像这样叫它:

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

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

其他回答

下面的一行代码就可以做到这一点:

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

更新新的Gson lib: 你现在可以直接将嵌套的Json解析为Map,但你应该意识到,如果你试图将Json解析为Map<String,对象>类型:它将引发异常。要解决这个问题,只需将结果声明为LinkedTreeMap类型。在下面的例子:

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

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

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

我使用下面的反序列化器来自然地反序列化任何东西,默认的JsonObjects到Map<String,对象>和JsonArrays到对象[]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;
  }
}

handlePrimitive方法内部的混乱是为了确保您只获得Double或Integer或Long,可能会更好,或者至少可以简化,如果您愿意获得bigdecimal,我相信这是默认的。

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

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

然后像这样叫它:

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

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

JSONObject通常在内部使用HashMap来存储数据。你可以在代码中使用它作为Map。

的例子,

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

我使用了下面的代码:

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