Android Gson parsing Json data process and how to customize parsing rules (middle)

​This article has participated in the "Newcomer Creation Ceremony" event to start the road to gold creation.

According to the previous article, we need to go through our own process for parsing the entry. We need a GsonConverFactory of our own, but we don't want to write other code. We just want to change the key places. We will definitely think of directly inheriting GsonConverFactory, but unfortunately, this class is final It cannot be inherited, so we can directly copy this class for processing and customize our own adapter step by step; our goal is to parse and customize the Object type and the Collect type.

Through the source code, it is found that most of the classes have the final keyword and cannot be inherited, so we can only copy a copy, there is no way.

First copy the CollectionTypeAdapterFactory, then copy what is missing, and then copy the ReflectiveTypeAdapterFactory as well

After some copying, the final files that need to be copied are as follows:

  • We find the read method corresponding to its corresponding WCollectionTypeAdapterFactory and change it as follows

        @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();
        }

In the same way, the WReflectiveTypeAdapterFactory parsing and modification of the Object type file is as follows:

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

?, the core part has been modified. Next, we need to apply all the changes to retrofit2. We find the copied WGsonConverFactory class. This class is our new conversion class. We need to make some modifications inside it. Two WReflectiveTypeAdapterFactory and WCollectionTypeAdapterFactory are registered in the Gson instance, replacing the original parser with our parser, as follows:

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

Finally, register it to retrofit2 and replace the original GsonConverFactory as follows:

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

Test Results:

WCollectionTypeAdapterFactory can be used normally, but the WReflectiveTypeAdapterFactory class cannot be used normally. It is estimated that because the JsonAdapterAnnotationTypeAdapterFactory class is in Gson, but WReflectiveTypeAdapterFactory initialization needs to use it, there is a sequence of Gson.create()-->Gson initialization generates JsonAdapterAnnotationTypeAdapterFactory, and initializes ReflectiveTypeAdapterFactory -- >Add to Gson, but before Gson is initialized when registering a custom parser, it cannot replace ReflectiveTypeAdapterFactory in Gson

Guess you like

Origin juejin.im/post/7116811188008452132