Android Gson 解析Json數據過程和如何自定義解析規則(中)

根據上篇文章,我們要把解析入口走我們自己的流程,我們需要一個自己的 GsonConverFactory 但是又不想寫其他代碼,只想改關鍵地方,我們肯定會想到直接繼承 GsonConverFactory 但是很遺憾,這個類帶final 不能被繼承,所以,我們可以直接把這個類複製一份處理,一步一步的自定義我們自己的適配器;我們的目標就是把Object類型和Collect類型解析自定義

通過源碼發現,大部分類都是帶final關鍵字,不能被繼承,所以我們只能複製一份出來,沒辦法。

首先把 CollectionTypeAdapterFactory複製出來 然後缺啥複製啥出來然後ReflectiveTypeAdapterFactory也是如此

經過一番複製,最後需要複製出的文件如下:

  • 我們找到其對應的 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章