问题
线下与后端联调时无异常,因为数据都是按着接口文档给的。但是有时到了线上,数据格式会因为一些脏数据,后端在返回数据时直接返回了不按接口格式给的数据结构。我们经常遇到的就是定义了 {}对象,给了[]数据,或者反过来,又或者数字类型返回了非数字类型等。造成了gson解析时报异常。
gson解析原理
- 注册定义好的TypeAdapter(gson自定定义了很多了,我们也可以自己定义(后添加的优先,通过GsonBuilder.registerTypeAdapterFactory添加(重点方法)))
- 将TypeAdapter封装成TypeAdapterFactory,然后加入Gson的factories(List)中
- 通过fromJson方法最终调用getAdapter,遍历factories,获取fromJson的第二个参数type与之对应的TypeAdapterFactory,调用该Factory的create方法来创建一个TypeAdapter
- 调用TypeAdapter的read方法完成json到相关类型的转换。(主要改这个方法)
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
reader.setLenient(true);
try {
reader.peek();
isEmpty = false;
TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
TypeAdapter<T> typeAdapter = getAdapter(typeToken);
T object = typeAdapter.read(reader);
return object;
} catch (EOFException e) {
/*
* For compatibility with JSON 1.5 and earlier, we return null for empty
* documents instead of throwing.
*/
if (isEmpty) {
return null;
}
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
throw new JsonSyntaxException(e);
} finally {
reader.setLenient(oldLenient);
}
}
将传进来类型转为typeToken,通过 typeToken 去找能解析此类型的TypeAdapter,寻找方法就是遍历List<TypeAdapterFactory> factories.
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
TypeAdapter<?> cached = typeTokenCache.get(type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// the key and value type parameters always agree
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
先从缓存中查找,有就直接返回,没有再去遍历查找,直到查找到能解析的adapter返回。
自定义TypeAdapter
gson默认构造初始化了很多类型的TypeAdapter
// type adapters for basic platform types
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
factories.add(TypeAdapters.BOOLEAN_FACTORY);
factories.add(TypeAdapters.BYTE_FACTORY);
factories.add(TypeAdapters.SHORT_FACTORY);
TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy);
factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
factories.add(TypeAdapters.newFactory(double.class, Double.class,
doubleAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.newFactory(float.class, Float.class,
floatAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.NUMBER_FACTORY);
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
factories.add(TypeAdapters.CHARACTER_FACTORY);
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
factories.add(TypeAdapters.URL_FACTORY);
factories.add(TypeAdapters.URI_FACTORY);
factories.add(TypeAdapters.UUID_FACTORY);
factories.add(TypeAdapters.CURRENCY_FACTORY);
factories.add(TypeAdapters.LOCALE_FACTORY);
解析对象类型的适配器ReflectiveTypeAdapterFactory,因为gson库里定义成final类型,我们不能通过继承去修改,只能copy一份修改其解析json串的方法,其内部声明了一个TypeAdapter内部类,修改其read方法
@Override
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return constructor.construct();
}
//增加判断是错误的ARRAY的类型(应该是object),移动in的下标到结束,移动下标的代码在下方
if (in.peek() == JsonToken.BEGIN_ARRAY) {
GsonTools.readArray(in);
return constructor.construct();
}
//增加判断是错误的NUMBER的类型(应该是object),移动in的下标到结束,移动下标的代码在下方
if (in.peek() == JsonToken.NUMBER) {
in.nextDouble();
return constructor.construct();
}
//增加判断是错误的String的类型(应该是object),移动in的下标到结束,移动下标的代码在下方
if (in.peek() == JsonToken.STRING) {
in.nextString();
return constructor.construct();
}
//增加判断是错误的name的类型(应该是object),移动in的下标到结束,移动下标的代码在下方
if (in.peek() == JsonToken.NAME) {
in.nextName();
return constructor.construct();
}
//增加判断是错误的bookean的类型(应该是object),移动in的下标到结束,移动下标的代码在下方
if (in.peek() == JsonToken.BOOLEAN) {
in.nextBoolean();
return constructor.construct();
}
T instance = constructor.construct();
try {
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
BoundField field = boundFields.get(name);
if (field == null || !field.deserialized) {
in.skipValue();
} else {
field.read(in, instance);
}
}
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
in.endObject();
return instance;
}
然后通过GsonBuilder的registerTypeAdapterFactory添加我们的修改后的ReflectiveTypeAdapterFactory即可
GsonBuilder gsonBuilder = new GsonBuilder();
Class builder = (Class) gsonBuilder.getClass();
Field f = null;
try {
//通过反射得到构造器
f = builder.getDeclaredField("instanceCreators");
f.setAccessible(true);
final Map<Type, InstanceCreator<?>> val = (Map<Type, InstanceCreator<?>>) f.get(gsonBuilder);//得到此属性的值
//注册String类型处理器
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(String.class,GsonTools.stringTypeAdapter()));
//注册int.class, Integer.class处理器
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(int.class, Integer.class, GsonTools.longAdapter(0)));
//注册short.class, Short.class处理器
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(short.class, Short.class, GsonTools.longAdapter(1)));
//注册long.class, Long.class处理器
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(long.class, Long.class, GsonTools.longAdapter(2)));
//注册double.class, Double.class处理器
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(double.class, Double.class, GsonTools.longAdapter(3)));
//注册float.class, Float.class处理器
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(float.class, Float.class, GsonTools.longAdapter(4)));
//注册反射对象的处理器
gsonBuilder.registerTypeAdapterFactory(new ReflectiveTypeAdapterFactory(new ConstructorConstructor(val), FieldNamingPolicy.IDENTITY, Excluder.DEFAULT));
//注册集合的处理器
gsonBuilder.registerTypeAdapterFactory(new CollectionTypeAdapterFactory(new ConstructorConstructor(val)));
} catch (Exception e) {
e.printStackTrace();
}
因为添加 gsonBuilder.registerTypeAdapterFactory(new ReflectiveTypeAdapterFactory(new ConstructorConstructor(val), FieldNamingPolicy.IDENTITY, Excluder.DEFAULT));
需要GsonBuilder类的一个私有变量,我们通过反射去取得这参数。