AndroidGson解析Json数据过程和如何⾃定义解析规则(上)友情提⽰:当前⽂章和(中)均为过程实际没有完美解决问题,真正解决问题的是
背景
Android开发与后台API对接时,使⽤Gson库做数据转换,但是实际测试发现不够灵活,当Gson处理正常数据时,整个流程是正确的,⽐如获取⽤户信息返回正确数据
{"code":200,"data":{"id":"adsd","name":"Weipru"},"msg":"success","timeStamp":"20191015102953"}
但是当你未登录或者遇到其他错误信息时,后台可能直接给你返回⼀个data没有对象的字段
{"code":1000,"data":"","msg":"请登录!","timeStamp":"20191014094718"}
这个时候如果还是⽤默认的GsonConverFactory解析,就会抛出⼀个错误:
Expected END_OBJECT but was String
导致整个请求回调失败的⽅法,同样,如果返回的数据是数组时也会出现类似的情,所以为了解决这些问题,需要重写⼏个转换器;
解读源码
我们来追溯⼀下错误的抛出原因,在创建 retrofit2请求时 会添加⼀个默认的Json解析器:
打开这个类可以看到两个关键函数 responseBodyConverter()和requestBodyConverter(),可以看出这⾥是请求Json转换数据的出⼝和后台响应Json解析数据的⼊⼝,我们要想⾃定义我们⾃⼰的解析⽅法,必须从这⾥下⼿。这⾥只看responseBodyConverter这个函数。
继续看,这个⽅法最后return了⼀个new GsonResponseBodyConverter对象,进去看⾥⾯只有⼀个函数 convert()
这个地⽅就是开始解析Json数据的地⽅,他根据你传⼊的Type 调⽤对应的解析器进⾏解析,⾄于解析器有多少呢,这⾥根据需要,⼤致分为三⼤类:基本值类型stirng,int,float等,引⽤类型Object和数组List等;在源码Gson类构造函数中可以到
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy,
final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
LongSerializationPolicy longSerializationPolicy,
List<TypeAdapterFactory> typeAdapterFactories) {
this.fieldNamingStrategy = fieldNamingStrategy;
this.serializeNulls = serializeNulls;
this.htmlSafe = htmlSafe;
this.prettyPrinting = prettyPrinting;
this.lenient = lenient;
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);
// user's type adapters
factories.addAll(typeAdapterFactories);
// 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.wFactory(long.class, Long.class, longAdapter));
factories.wFactory(double.class, Double.class,
doubleAdapter(serializeSpecialFloatingPointValues)));
factories.wFactory(float.class, Float.class,
floatAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.NUMBER_FACTORY);
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
factories.wFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
factories.wFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter))); factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
android retrofitfactories.add(TypeAdapters.CHARACTER_FACTORY);
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
factories.wFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
factories.wFactory(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);
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
factories.add(TypeAdapters.BIT_SET_FACTORY);
factories.add(DateTypeAdapter.FACTORY);
factories.add(TypeAdapters.CALENDAR_FACTORY);
factories.add(TimeTypeAdapter.FACTORY);
factories.add(SqlDateTypeAdapter.FACTORY);
factories.add(TypeAdapters.TIMESTAMP_FACTORY);
factories.add(ArrayTypeAdapter.FACTORY);
factories.add(TypeAdapters.CLASS_FACTORY);
// type adapters for composite and user-defined types
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
factories.add(jsonAdapterFactory);
factories.add(TypeAdapters.ENUM_FACTORY);
factories.add(new ReflectiveTypeAdapterFactory(
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
this.factories = Collections.unmodifiableList(factories);
}
可以清楚发现 Gson类在初始化时为⾃⼰注册了各种类型的Json类型解析器TypeAdapterFactory,其中 包含两个关键的解析器CollectionTypeAdapterFactory和 ReflectiveTypeAdapterFactory他们都实现了接⼝TypeAdapterFactory,⼀个是list的解析,另外⼀个是Object的解析,也是我们要改的⽬标。
根据⼀番调试,解析数据时均从调⽤⾃⾝的read()⽅法进⾏解析,看源码ReflectiveTypeAdapterFactory:
@Override public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
return null;
}
T instance = struct();
try {
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
BoundField field = (name);
if (field == null || !field.deserialized) {
in.skipValue();
} else {
}
}
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
return instance;
}
打开JsonReader.beginObject() :
public void beginObject() throws IOException {
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
if (p == PEEKED_BEGIN_OBJECT) {//关键条件
push(JsonScope.EMPTY_OBJECT);
peeked = PEEKED_NONE;
} else {
throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek() + locationString());
}
}
可以看到,P是代表当前读取到的Json数据类型,⽐如{"name","wpr","data":{}}中,读取到 " 时,p就代表STRING 类型,同理,{ 就是Object类型;在上⾯代码中,如果请求时这样写
Call<HttpMessage<UserInfo>> messageCall=retrofit2的API;//发起请求
后台返回Json数据
{"code":1000,"data":"","msg":"请登录!","timeStamp":"20191014094718"}
那么当读取到data字段时,他的值开头时"分号,这个时候p就是STRING了,直接就⾛else 给你抛出
Expected BEGIN_OBJECT but was ************
最后请求回调失败的函数,同理 其他异常也是如此***************
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论