解决gson解析类型不对数据crash

问题

线下与后端联调时无异常,因为数据都是按着接口文档给的。但是有时到了线上,数据格式会因为一些脏数据,后端在返回数据时直接返回了不按接口格式给的数据结构。我们经常遇到的就是定义了 {}对象,给了[]数据,或者反过来,又或者数字类型返回了非数字类型等。造成了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 fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
    boolean isEmpty = true;
    boolean oldLenient = reader.isLenient();
    reader.setLenient(true);
    try {
      reader.peek();
      isEmpty = false;
      TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT);
      TypeAdapter 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 factories.
public  TypeAdapter getAdapter(TypeToken type) {
    TypeAdapter cached = typeTokenCache.get(type);
    if (cached != null) {
      return (TypeAdapter) cached;
    }

    Map, FutureTypeAdapter> threadCalls = calls.get();
    boolean requiresThreadLocalCleanup = false;
    if (threadCalls == null) {
      threadCalls = new HashMap, FutureTypeAdapter>();
      calls.set(threadCalls);
      requiresThreadLocalCleanup = true;
    }

    // the key and value type parameters always agree
    FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type);
    if (ongoingCall != null) {
      return ongoingCall;
    }

    try {
      FutureTypeAdapter call = new FutureTypeAdapter();
      threadCalls.put(type, call);

      for (TypeAdapterFactory factory : factories) {
        TypeAdapter 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 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> val = (Map>) 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类的一个私有变量,我们通过反射去取得这参数。

常用的类型的adapter

常用的类型的adapter做了一些判空,数据类型错误的校验。传到github,欢迎共同交流
https://github.com/850125665/MGson


你可能感兴趣的:(android)