Android Gson 解析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,
      boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
      boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
      LongSerializationPolicy longSerializationPolicy,
      List<TypeAdapterFactory> typeAdapterFactories) {
    this.constructorConstructor = new ConstructorConstructor(instanceCreators);
    this.excluder = excluder;
    this.fieldNamingStrategy = fieldNamingStrategy;
    this.serializeNulls = serializeNulls;
    this.generateNonExecutableJson = generateNonExecutableGson;
    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.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);
    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 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,其中 包含两个关键的解析器 CollectionTypeAdapterFactoryReflectiveTypeAdapterFactory他们都实现了接口TypeAdapterFactory,一个是list的解析,另外一个是Object的解析,也是我们要改的目标。

根据一番调试,解析数据时均从调用自身的read()方法进行解析,看源码ReflectiveTypeAdapterFactory:

 @Override public T read(JsonReader in) throws IOException {
      if (in.peek() == JsonToken.NULL) {
        in.nextNull();
        return null;
      }

      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;
    }

打开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 ************

最后请求回调失败的函数,同理 其他异常也是如此***************

下一篇将解析如何处理这种问题

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值