Android Gson analisando o processo de dados Json e como personalizar as regras de análise (meio)

​Este artigo participou do evento "Newcomer Creation Ceremony" para iniciar o caminho para a criação de ouro.

De acordo com o artigo anterior, precisamos passar por nosso próprio processo para analisar a entrada. Precisamos de um GsonConverFactory próprio, mas não queremos escrever outro código. Queremos apenas alterar os locais principais. Com certeza, pense em herdar diretamente GsonConverFactory, mas infelizmente, esta classe é final Não pode ser herdada, então podemos copiar diretamente esta classe para processar e personalizar nosso próprio adaptador passo a passo; nosso objetivo é analisar e personalizar o tipo Object e o tipo Collect .

Através do código-fonte, verifica-se que a maioria das classes possui a palavra-chave final e não pode ser herdada, então só podemos copiar uma cópia, não tem como.

Primeiro copie o CollectionTypeAdapterFactory, depois copie o que está faltando e copie também o ReflectiveTypeAdapterFactory

Após algumas cópias, os arquivos finais que precisam ser copiados são os seguintes:

  • Encontramos o método read correspondente ao seu WCollectionTypeAdapterFactory correspondente e o alteramos da seguinte forma

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

Da mesma forma, a análise e modificação WReflectiveTypeAdapterFactory do arquivo de tipo Object é a seguinte:

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

?, a parte principal foi modificada. Em seguida, precisamos aplicar todas as alterações ao retrofit2. Encontramos a classe WGsonConverFactory copiada. Essa classe é nossa nova classe de conversão. Precisamos fazer algumas modificações dentro dela. Duas WReflectiveTypeAdapterFactory e WCollectionTypeAdapterFactory são registrado na instância Gson, substituindo o analisador original pelo nosso analisador, da seguinte forma:

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

Por fim, registre-o no retrofit2 e substitua o GsonConverFactory original da seguinte forma:

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

Resultado dos testes:

WCollectionTypeAdapterFactory pode ser usado normalmente, mas a classe WReflectiveTypeAdapterFactory não pode ser usada normalmente. Estima-se que porque a classe JsonAdapterAnnotationTypeAdapterFactory está em Gson, mas a inicialização WReflectiveTypeAdapterFactory precisa usá-la, existe uma sequência de Gson.create()-->inicialização Gson gera JsonAdapterAnnotationTypeAdapterFactory e inicializa ReflectiveTypeAdapterFactory --> Adicionar ao Gson, mas antes que o Gson seja inicializado ao registrar um analisador personalizado, ele não pode substituir ReflectiveTypeAdapterFactory no Gson

Acho que você gosta

Origin juejin.im/post/7116811188008452132
Recomendado
Clasificación