Android Gson 解析Json数据过程和如何自定义解析规则(中)

​本文已参与「新人创作礼」活动,一起开启创作之路。

根据上篇文章,我们要把解析入口走我们自己的流程,我们需要一个自己的 GsonConverFactory 但是又不想写其他代码,只想改关键地方,我们肯定会想到直接继承GsonConverFactory 但是很遗憾,这个类带final 不能被继承,所以,我们可以直接把这个类复制一份处理,一步一步的自定义我们自己的适配器;我们的目标就是把Object类型和Collect类型解析自定义

通过源码发现,大部分类都是带final关键字,不能被继承,所以我们只能复制一份出来,没办法。

首先把 CollectionTypeAdapterFactory复制出来 然后缺啥复制啥出来然后ReflectiveTypeAdapterFactory也是如此

经过一番复制,最后需要复制出的文件如下:

Android Gson 解析Json数据过程和如何自定义解析规则(中)
Android Gson 解析Json数据过程和如何自定义解析规则(中)

  • 我们找到其对应的 WCollectionTypeAdapterFactory对应的read方法,按照如下更改

        @Override
        public Collection<E> read(JsonReader in) throws IOException {
            JsonToken peek = in.peek();
            if (peek == JsonToken.NULL) {
                in.nextNull();
                return constructor.construct();//改动
            } else if (peek != JsonToken.STRING) {//改动
                Collection<E> collection = constructor.construct();
                in.beginArray();
                while (in.hasNext()) {
                    E instance = elementTypeAdapter.read(in);
                    collection.add(instance);
                }
                in.endArray();
                return collection;
            }
            //必须要跳过不能解析的value,防止出现{arr:""}这种情况,指针停留在双引号之间,导致解析下一个name时出现空而爆粗
            in.nextString();
            return constructor.construct();
        }

同理,对Object类型的文件WReflectiveTypeAdapterFactory解析修改如下:

  @Override
        public T read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return null;
            }
            //如果是字符串,说明没有正确的数据 不能继续往下走,直接返回new的对象
            if (in.peek() == JsonToken.STRING) {
                in.nextString();//一定要调用这句话使jsonReader读取指针走到下一个字段中
                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;
        }

?,核心部分已完成修改,接下来需要把所有的改动应用至retrofit2中,我们找到复制出来的WGsonConverFactory类,这个类作为我们新的转换类,其内部我们需要做点修改,把我们上面复制的两个WReflectiveTypeAdapterFactoryWCollectionTypeAdapterFactory注册到Gson实例中,把原来的解析器替换成我们的解析器,如下:

public class WGsonConverFactory extends Converter.Factory {
    private static final String TAG = "WGSON";
    //主要改动在这里
    public static WGsonConverFactory create() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        //通过反射获取各种属性 为其更换类型处理器
        try {
            Class builder = gsonBuilder.getClass();
            Field f = builder.getDeclaredField("instanceCreators");
            f.setAccessible(true);
            Map<Type, InstanceCreator<?>> val = (Map<Type, InstanceCreator<?>>) f.get(gsonBuilder);//得到此属性的值
            Field namingStra = builder.getDeclaredField("fieldNamingPolicy");
            namingStra.setAccessible(true);
            FieldNamingStrategy fieldNamingPolicy = (FieldNamingStrategy) namingStra.get(gsonBuilder);
            Field filedExcluder = builder.getDeclaredField("excluder");
            filedExcluder.setAccessible(true);
            Excluder excluder = (Excluder) filedExcluder.get(gsonBuilder);
            //这个类由于反射拿不到数据,所以也把他复制出来,直接new即可
            JsonAdapterAnnotationTypeAdapterFactory jsonAdapterAnnotationTypeAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(new ConstructorConstructor(val));
            //注册数组的处理器
            gsonBuilder.registerTypeAdapterFactory(new WCollectionTypeAdapterFactory(new ConstructorConstructor(val)));
            gsonBuilder.registerTypeAdapterFactory(jsonAdapterAnnotationTypeAdapterFactory);
            //注册Object;类型处理器
            gsonBuilder.registerTypeAdapterFactory(new WReflectiveTypeAdapterFactory(new ConstructorConstructor(val), fieldNamingPolicy, excluder, jsonAdapterAnnotationTypeAdapterFactory));
        } catch (NoSuchFieldException e) {
            Log.e(TAG, "可能出现某个字段丢失导致多个类型适配器反射注册失败,这可能会影响之后的json数据解析 ", e);
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return create(gsonBuilder.create());
    }
    @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
    public static WGsonConverFactory create(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        return new WGsonConverFactory(gson);
    }
    private final Gson gson;
    private WGsonConverFactory(Gson gson) {
        this.gson = gson;
    }
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        Log.w("TYPE", "类型是 " + type.getTypeName());//
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new WGsonResponseBodyConverter<>(gson, adapter);
    }
    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new WGsonRequestBodyConverter<>(gson, adapter);
    }
}

最后,将其注册到retrofit2,替换原来的GsonConverFactory, 使用方法如下:

 this.host = GlobalStatusDataManager.getInstance().getHostPort();
        File cacheDirectory = new File(context
                .getCacheDir().getAbsolutePath(), "HttpCache");
        builder = new OkHttpClient.Builder();
        builder.addInterceptor(new HttpGlobalIntercepter());
        builder.connectTimeout(TIMEOUT, TimeUnit.SECONDS);
        builder.readTimeout(TIMEOUT, TimeUnit.SECONDS);
        builder.writeTimeout(TIMEOUT, TimeUnit.SECONDS);
        builder.cache(new Cache(cacheDirectory, 10 * 1024 * 1024));
        userServiceAPI = new Retrofit.Builder()
                .client(builder.build())
                .baseUrl(this.host).addConverterFactory(WGsonConverFactory.create())//使用我们自己的转换器
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build()
                .create(GsonTestAPI.class);

测试结果:

WCollectionTypeAdapterFactory 能正常使用,但是WReflectiveTypeAdapterFactory 这个类不能正常使用,估计由于JsonAdapterAnnotationTypeAdapterFactory这个类在Gson中,然而WReflectiveTypeAdapterFactory初始化需要用到他,存在先后顺序Gson.create()–>Gson初始化产生JsonAdapterAnnotationTypeAdapterFactory,初始化ReflectiveTypeAdapterFactory–>add到Gson中,但是注册自定义解析器时需要在Gson初始化前,所以无法替换Gson中ReflectiveTypeAdapterFactory

评论

发表回复