Gson:有没有更简单的方法来序列化地图

时间:2011-12-02 18:24:43

标签: java json gson

来自Gson项目的

This链接似乎表明我必须做类似以下的事情来将类型化的Map序列化为JSON:

    public static class NumberTypeAdapter 
      implements JsonSerializer<Number>, JsonDeserializer<Number>,
InstanceCreator<Number> {

    public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext
context) {
      return new JsonPrimitive(src);
    }

    public Number deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
        throws JsonParseException {
      JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();
      if (jsonPrimitive.isNumber()) {
        return jsonPrimitive.getAsNumber();
      } else {
        throw new IllegalStateException("Expected a number field, but was " + json);
      }
    }

    public Number createInstance(Type type) {
      return 1L;
    }
  }

  public static void main(String[] args) {
    Map<String, Number> map = new HashMap<String, Number>();    
    map.put("int", 123);
    map.put("long", 1234567890123456789L);
    map.put("double", 1234.5678D);
    map.put("float", 1.2345F);
    Type mapType = new TypeToken<Map<String, Number>>() {}.getType();

    Gson gson = new GsonBuilder().registerTypeAdapter(Number.class, new
NumberTypeAdapter()).create();
    String json = gson.toJson(map, mapType);
    System.out.println(json);

    Map<String, Number> deserializedMap = gson.fromJson(json, mapType);
    System.out.println(deserializedMap);
  }

酷而且有效,但似乎有很多开销( 一个完整的Type Adapter类? )。我已经使用了其他JSON库,比如JSONLib,它们允许您以下列方式构建地图:

JSONObject json = new JSONObject();
for(Entry<String,Integer> entry : map.entrySet()){
     json.put(entry.getKey(), entry.getValue());
}

或者,如果我有一个类似于以下内容的自定义类:

JSONObject json = new JSONObject();
for(Entry<String,MyClass> entry : map.entrySet()){
 JSONObject myClassJson =  JSONObject.fromObject(entry.getValue());
     json.put(entry.getKey(), myClassJson);
}

该过程更加手动,但需要更少的代码,并且没有为数字创建自定义类型适配器的开销,或者在大多数情况下 用于我自己的自定义类

这是使用Gson序列化地图的唯一方法,还是有人找到了一种方法,可以击败Gson在上面链接中推荐的内容。

5 个答案:

答案 0 :(得分:114)

只有TypeToken部分是必要的(当涉及遗传学时)。

Map<String, String> myMap = new HashMap<String, String>();
myMap.put("one", "hello");
myMap.put("two", "world");

Gson gson = new GsonBuilder().create();
String json = gson.toJson(myMap);

System.out.println(json);

Type typeOfHashMap = new TypeToken<Map<String, String>>() { }.getType();
Map<String, String> newMap = gson.fromJson(json, typeOfHashMap); // This type must match TypeToken
System.out.println(newMap.get("one"));
System.out.println(newMap.get("two"));

输出:

{"two":"world","one":"hello"}
hello
world

答案 1 :(得分:84)

默认

Map序列化的默认Gson实现在密钥上使用toString()

Gson gson = new GsonBuilder()
        .setPrettyPrinting().create();
Map<Point, String> original = new HashMap<>();
original.put(new Point(1, 2), "a");
original.put(new Point(3, 4), "b");
System.out.println(gson.toJson(original));

会给:

{
  "java.awt.Point[x\u003d1,y\u003d2]": "a",
  "java.awt.Point[x\u003d3,y\u003d4]": "b"
}

<小时/>

使用enableComplexMapKeySerialization

如果您希望根据默认的Gson规则序列化Map Key,可以使用enableComplexMapKeySerialization。这将返回一组键值对数组:

Gson gson = new GsonBuilder().enableComplexMapKeySerialization()
        .setPrettyPrinting().create();
Map<Point, String> original = new HashMap<>();
original.put(new Point(1, 2), "a");
original.put(new Point(3, 4), "b");
System.out.println(gson.toJson(original));

将返回:

[
  [
    {
      "x": 1,
      "y": 2
    },
    "a"
  ],
  [
    {
      "x": 3,
      "y": 4
    },
    "b"
  ]
]

可以找到更多详细信息here

答案 2 :(得分:4)

我很确定GSON默认情况下序列化/反序列化地图和多嵌套地图(即Map<String, Map<String, Object>>)。如果您需要做一些更复杂的事情,我认为这个例子只不过是一个起点。

查看GSON源中的MapTypeAdapterFactory类:http://code.google.com/p/google-gson/source/browse/trunk/gson/src/main/java/com/google/gson/internal/bind/MapTypeAdapterFactory.java

只要键和值的类型可以序列化为JSON字符串(并且您可以为这些自定义对象创建自己的序列化器/反序列化器),就不应该有任何问题。

答案 3 :(得分:3)

在Gson 2.7.2中,它就像

一样简单
Gson gson = new Gson();
String serialized = gson.toJson(map);

答案 4 :(得分:-3)

Map<String, Object> config = gson.fromJson(reader, Map.class);