以下都是个人通过看gson源码所得,欢迎指正。
用GsonBuilder来创建Gson
GsonBuilder有以下主要的功能:
1、 serializeNulls:把json中的””,转换为null;
2、 setPrettyPrinting:把json无格式字符串转换为带格式的字符串;
3、 excludeFieldsWithModifiers(Modifier.PRIVATE):Gson在解析时,把类中字段的PRIVATE访问权限排除,就是遇到private修饰的字段时,Gson不做解析;(还可以对有final,static等修饰的变量,或者修饰类的abstract,或者类是接口的等等,都可以做出控制解析)
4、 setExclusionStrategies:Gson解析时,可以通过名字排除某些字段,也可以通过类型排除,不做解析;如Gson gson = newGsonBuilder().
setExclusionStrategies(myExclusionStrategy).create();其中需要重写ExclusionStrategy中的两个方法,如下:
ExclusionStrategy myExclusionStrategy = new ExclusionStrategy() {
@Override
public booleanshouldSkipField(FieldAttributes fa) {
return fa.getName().startsWith("serializationFieldSet")||fa.getName().startsWith("unknownFieldSet");
}
@Override
public booleanshouldSkipClass(Class<?> clazz) {
return false;
}
};其中shouldSkipField()是根据字段名字来过滤是否解析,shouldSkipClass()是根据类型来判断是否解析。
5、 setLongSerializationPolicy:设置对Long类型的变量,是解析成字符串还是解析为long类型,可以这样设置如下:Gson gson = newGsonBuilder. setLongSerializationPolicy(LongSerializationPolicy.DEFAULT).create(),其中LongSerializationPolicy.DEFAULT为默认值,Long类型转换为Long型,LongSerializationPolicy.STRING为字符串型,就是把Long类型的值强制转换为字符串类型。
6、 excludeFieldsWithoutExposeAnnotation():主要是不解析@Expose修饰的字段。
7、 generateNonExecutableJson():生成的json字符串不具备正确格式的json字符串。
8、 setDateFormat("yyyy-MM-dd HH:mm:ss"):把解析后的是Date类型的字段格式都转换为yyyy-MM-dd HH:mm:ss类型,Gson对日期设置的有好三种,不在累述,网上也有。
9、 如果上述方式还不能解决你的问题,就可以采用稍微复杂的方式,通过解析过程中的序列化和反序列化来解决问题,在序列化时,把数据保存为某种形式,反序列化时把数据根据保存的那种形式解析出来,如:
Gson gson = new GsonBuilder().registerTypeAdapterFactory(newIntEnumTypeAdapterFactory());注册一个类型适配工厂,在这个工厂中创建你要的类型适配器,然后在你的类型适配器中重写序列化和反序列化这两个方法,如下:
package feinno.proxy.util;
importjava.io.IOException;
importjava.util.HashMap;
importjava.util.Map;
importcom.feinno.util.EnumInteger;
importcom.google.gson.Gson;
importcom.google.gson.TypeAdapter;
importcom.google.gson.TypeAdapterFactory;
importcom.google.gson.reflect.TypeToken;
importcom.google.gson.stream.JsonReader;
importcom.google.gson.stream.JsonToken;
importcom.google.gson.stream.JsonWriter;
public classIntEnumTypeAdapterFactory implements TypeAdapterFactory{
@Override
public <Enum> TypeAdapter<Enum>create(Gson gson, TypeToken<Enum> type) {
Class<Enum> rawType =(Class<Enum>) type.getRawType();
if (!rawType.isEnum()) {
return null;
}
final Map<String, Enum>defaultValue = new HashMap<String, Enum>();
final Map<String, Integer> ttMap =new HashMap<String, Integer>();
for(Enum constant : rawType.getEnumConstants()) {
if (constant instanceof EnumInteger) {
EnumInteger enumInteger = (EnumInteger)constant;
ttMap.put(constant.toString(),enumInteger.intValue());
}elsedefaultValue.put(constant.toString(), constant);
}
return new TypeAdapter<Enum>() {
public void write(JsonWriter out, Enumvalue) throws IOException {
if (value == null) {
out.nullValue();
} else {
if (value instanceofEnumInteger) out.value(ttMap.get(value.toString()));
else out.value(defaultValue.get(value.toString()).toString());
}
}
public Enum read(JsonReader reader)throws IOException {
if (reader.peek() == JsonToken.NULL){
reader.nextNull();
return null;
} else {
returndefaultValue.get(reader.nextString());
}
}
};
}
}
IntEnumTypeAdapterFactory这个类的主要作用就是把继承EnumInteger的枚举类,解析为数字,因为如果不做任何改变,解析后返回的值是字符串,不是数字。Write方法首先判断是否为枚举类,若是再判断属性是否是EnumInteger类型,如果是就把字符串,数字形式的map,如果不是就存为字符串,枚举类形式的map,反序列化时,直接根据字符串来取值,就可以取到数字。
总结(个人意见,仅供参考):
Gson给我们提供的接口基本上都是通过类型适配器工厂把提供的那几个接口作为新的类型适配器,在每次解析时,都会循环有哪些类型适配器,用它们重写过的序列化反序列化方法,所以在Gson提供的那些接口解决不了问题时,就new一个新的TypeAdapater(类型适配器),重写write和read方法,然后把它注册到类型适配器工厂。