根據上篇文章,我們要把解析入口走我們自己的流程,我們需要一個自己的 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類,這個類作爲我們新的轉換類,其內部我們需要做點修改,把我們上面複製的兩個WReflectiveTypeAdapterFactory和WCollectionTypeAdapterFactory註冊到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