Gson:有没有更简单的方法来序列化地图
从Gson项目的这个链接似乎表明,我将不得不做类似下面的序列化一个types的地图到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); }
很酷,这工作,但似乎是这么多的开销( 一个整体types适配器类? )。 我已经使用了JSONLib等其他JSON库,并且可以通过以下方式构build地图:
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); }
这个过程是更加手动的,但是需要更less的代码,并且没有为数字创build自定义types适配器的开销,或者在大多数情况下为我自己的自定义类创build开销。
这是使用Gson序列化地图的唯一方法,或者有人find了一个方法,击败了Gson在上面的链接build议。
只有TypeToken部分是必要的(当涉及generics时)。
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
默认
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
如果你想Map Map按照默认的Gson规则被序列化,你可以使用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" ] ]
更多细节可以在这里find。
我很确定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
只要键和值的types可以被序列化为JSONstring(并且可以为这些自定义对象创build自己的序列化器/反序列化器),则不应该有任何问题。
在Gson 2.7.2中,它非常简单
Gson gson = new Gson(); String serialized = gson.toJson(map);
Map<String, Object> config = gson.fromJson(reader, Map.class);