Gson 对 Map<String, Object> 嵌套类型的序列化与反序列化
gson 简介:
Gson is a Java library that can be used to convert Java Objects into its JSON representation
gson 扩展的一种方式:通过com.google.gson.GsonBuilder 注册TypeAdapter:
demo code:
import java.io.Serializable; import java.lang.reflect.Type; import java.text.DateFormat; import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; public class Demo { public Demo(){ Gson gson = new GsonBuilder() .registerTypeAdapter(Id.class, new IdTypeAdapter()) .serializeNulls() .setDateFormat(DateFormat.LONG) .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE) .setPrettyPrinting() .setVersion(1.0) .create(); Id id = new Id(); gson.toJson(id, Id.class); } public static class Id implements Serializable{ private static final long serialVersionUID = -7698012176465651638L; } public static class IdTypeAdapter implements JsonSerializer<Id>, JsonDeserializer<Id> { @Override public JsonElement serialize(Id src, Type typeOfSrc, JsonSerializationContext context) { //TODO serialize id type here return null; } @Override public Id deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { // TODO deserialize Id type here return null; } } }
遇到的问题:
遇到这样的情况,对于现有的随机的数据(数据格式无法确定,类型复杂),需要使用 Map<String, Object> 类型于json格式互相转换,其中Map中的Object类型的value可能会是Map<String, Object>.现有的gson版本会遇到 无法序列化或者无法反序列化,因为gson是通过Map<String, Object> 去确定value的类型为Object.class,无法进一步序列化。
改进:
照猫画虎,扩展现有的com.google.gson.DefaultTypeAdapters.MapTypeAdapter(此类为package visible, 要么copy代码,要么让自己的package为com.google.gson)
代码demo:
package com.google.gson; import java.lang.reflect.Type; import java.util.Map; import java.util.Set; import com.google.gson.DefaultTypeAdapters.MapTypeAdapter; public class FixedMapTypeAdapter extends MapTypeAdapter { @SuppressWarnings("unchecked") @Override public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) { JsonObject map = new JsonObject(); for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) { Object value = entry.getValue(); JsonElement valueElement; if (value == null) { valueElement = JsonNull.createJsonNull(); } else { Type childType = value.getClass(); valueElement = context.serialize(value, childType); } map.add(String.valueOf(entry.getKey()), valueElement); } return map; } @SuppressWarnings("unchecked") @Override public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { // Use ObjectConstructor to create instance instead of hard-coding a // specific type. // This handles cases where users are using their own subclass of Map. Map<Object, Object> map = constructMapType(typeOfT, context); TypeInfoMap mapTypeInfo = new TypeInfoMap(typeOfT); for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject() .entrySet()) { Object key = context.deserialize(new JsonPrimitive(entry.getKey()), mapTypeInfo.getKeyType()); JsonElement jsonElement = entry.getValue(); String jsonValue = jsonElement.toString(); Type valueType = mapTypeInfo.getValueType(); if(jsonValue.startsWith("{")){ valueType = new ParameterizedTypeImpl(Map.class, new Type[]{String.class, Object.class}, null); } Object value = context.deserialize(jsonElement, valueType); map.put(key, value); } return map; } @SuppressWarnings("unchecked") private Map constructMapType(Type mapType, JsonDeserializationContext context) { JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context; ObjectConstructor objectConstructor = contextImpl .getObjectConstructor(); return (Map) objectConstructor.construct(mapType); }
使用方式:
private final Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new FixedMapTypeAdapter()).create();
局限:
这样仅仅解决了gson对于嵌套的Map<String, Object>类型的序列化与反序列化,并且要求Map中的value为primative type or
Map<String, Object>(代码42行,使用“{”作为判断是否为complex value type)