【问题标题】:Deserializing Map<Object, Object> with GSon使用 GSon 反序列化 Map<Object, Object>
【发布时间】:2011-03-22 19:14:41
【问题描述】:

我有一个包含多种类型的地图,就像这个简单的例子一样

final Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("a", 1);
map.put("b", "a");
map.put("c", 2);
final Gson gson = new Gson();
final String string = gson.toJson(map);
final Type type = new TypeToken<LinkedHashMap<String, Object>>(){}.getType();
final Map<Object, Object> map2 = gson.fromJson(string, type);
for (final Entry<Object, Object> entry : map2.entrySet()) {
    System.out.println(entry.getKey() + " : " + entry.getValue());
}

我得到的只是Objects,没有Integers,没有Strings。输出看起来像

a : java.lang.Object@48d19bc8
b : java.lang.Object@394a8cd1
c : java.lang.Object@4d630ab9

我能以某种方式修复它吗?我希望默认情况下会正确处理这种简单的情况。

我知道关于类型的信息不能总是保留,可能1"1" 在JSON 中的意思完全一样。但是,返回普通的无内容对象对我来说毫无意义。

更新:序列化版本(即上面的string)看起来不错:

{"a":1,"b":"a","c":2}

【问题讨论】:

  • 您能看看final String string 的样子吗?我相信这将有助于理解问题。
  • 我也遇到过这种情况...这就是我使用 JSONer 的原因...它可能会慢一些,但它比 Gson 更通用:nu-art-infrastructure.blogspot.co.il/2013/03/jsoner.html
  • @TacB0sS:我遵循了“清晰和静态数据结构”的建议。然而,让 Gson 处理这个问题应该是微不足道的。你愿意提出问题吗?
  • 这件事的可怕之处在于,我将 GSON 与 Android 一起使用,并且在我的手机上运行良好,而在其他手机上它会创建您所描述的内容......我的解决方案也很明确静态的,但在 JSONer 解析器中,您可以使用带有嵌套复杂对象的地图和列表,这一切都在注解中解决了!
  • 想提出关于什么的问题?他们不知道这个问题吗?

标签: java object gson


【解决方案1】:

Gson 没那么聪明。而是以 Javabean 类的形式提供清晰的静态数据结构,以便 Gson 了解应该将单独的属性反序列化为什么类型。

例如

public class Data {
    private Integer a;
    private String b;
    private Integer c;
    // ...
}

结合

Data data1 = new Data(1, "a", 2);
String json = gson.toJson(data1);
Data data2 = gson.fromJson(json, Data.class);

更新:根据 cmets,keyset 似乎不是固定的(尽管您似乎可以在事后手动转换它而不事先知道结构)。您可以创建一个custom deserializer。这是一个简单粗暴的例子。

public class ObjectDeserializer implements JsonDeserializer<Object> {

    @Override
    public Object deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException {
        String value = element.getAsString();
        try {
            return Long.valueOf(value);
        } catch (NumberFormatException e) {
            return value;
        }
    }

}

你使用如下:

final Gson gson = new GsonBuilder().registerTypeAdapter(Object.class, new ObjectDeserializer()).create();
// ... 

【讨论】:

  • Javabean 肯定是不可能的,因为键集不是固定的。作为一种解决方法,我可以使用 Map&lt;String, String&gt; 并手动转换类型(类似这样),我只是想知道为什么 GSon 的行为如此奇怪。
  • 手动转换类型的能力表明您事先了解数据结构。所以 keyset 不固定的论点是非论点。至于 Gson,您可以考虑使用自定义反序列化器来确定值是否为数字(正则表达式、解析器、Long#valueOf() 等)并返回LongString。另见sites.google.com/site/gson/…
  • 我用一个例子更新了答案,你可能会发现它很有用。
  • “所以 keyset 不固定的论点是非论点。” - 这个“非论点”使 Javabean 解决方案无效。但是对于ObjectDeserializer 示例,它工作得很好。
  • 假设 Map 是一个 Javabean,是的。 ;)
【解决方案2】:
Gson gson = new GsonBuilder()
    .registerTypeAdapter(Object.class, new JsonDeserializer<Object>() {
      @Override
      public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonPrimitive value = json.getAsJsonPrimitive();
        if (value.isBoolean()) {
          return value.getAsBoolean();
        } else if (value.isNumber()) {
          return value.getAsNumber();
        } else {
          return value.getAsString();
        }
      }
    }).create();

【讨论】:

    【解决方案3】:

    升级到Gson 2.1。它打印这个:

    a : 1.0
    b : a
    c : 2.0
    

    【讨论】:

      【解决方案4】:

      您将数据存储在地图中。看起来您需要将对象转换为所需的类型。

      【讨论】:

      • 肯定不行,如果类型是String或者Integer,就不能输出java.lang.Object@...。我还使用getClass() 仔细检查了它。
      【解决方案5】:

      如果你想要来自 Map&lt;Object, Object&gt; 的 JSON 字符串,我认为 json-simpleGson 更好。

      这是来自http://code.google.com/p/json-simple/wiki/EncodingExamples 的一个简短示例:

      //import java.util.LinkedHashMap;
      //import java.util.Map;
      //import org.json.simple.JSONValue;
      
      Map obj=new LinkedHashMap();
      obj.put("name","foo");
      obj.put("num",new Integer(100));
      obj.put("balance",new Double(1000.21));
      obj.put("is_vip",new Boolean(true));
      obj.put("nickname",null);
      String jsonText = JSONValue.toJSONString(obj);
      System.out.print(jsonText);
      

      结果:{"name":"foo","num":100,"balance":1000.21,"is_vip":true,"nickname":null}

      解码请参考http://code.google.com/p/json-simple/wiki/DecodingExamples

      【讨论】:

        猜你喜欢
        • 2012-12-25
        • 2013-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-19
        相关资源
        最近更新 更多