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