對於gson我們很熟悉了
常用的複雜對象的gson解析方式:
Type listType = new TypeToken<ArrayList> () {}.getType();
但這一次我需要實現對
Type listType = new TypeToken<ArrayList> () {}.getType();的解析,
當我傳入泛型T=Port IP時,返回結果並非我預期的ArrayList,而是ArrayList,爲啥呢?
一開始我懷疑時kotlin泛型的問題,用java寫了一遍,結果同樣
然後我懷疑是gson的問題,搜了一下果然有人跟我一樣。
原因:
Gson解析時TypeToken的泛型參數只能在使用時傳入確切的類型才能獲取正確的Type, 這是TypeToken設計成抽象類的巧妙之處和原因,也是此次問題出現的原因。
(改爲只有protected構造方法的普通類原理一樣). 一旦將TypeToken改成普通類, 根據上面的分析, 一切類型信息都被擦除, Gson解析將得不到預期的類型,但是強大的gson組件幫了我們一把,把結果解析成LinkedTreeMap了。
那怎麼辦呢?
寫抽象類搞定 TypeToken<ArrayList> 這段
public abstract class GsonType<T> {
Type type;
public GsonType(){
Type genericSuperclass = getClass().getGenericSuperclass();
if(genericSuperclass instanceof Class){
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
type = typeArguments[0];
}
public Type getType() {
return type;
}
}
//使用
//給type賦值
saveDataHelper.gsonType = object: GsonType<ArrayList<PortIP>>(){}
//解析
mDatas =saveDataToJsonHelper.mGson.fromJson(jsonStr, gsonType.getType()) ;
上述代碼是參考的,原文解析
然後我看了看TypeToken的源碼發現
this.type = getSuperclassTypeParameter(getClass());
/**
* Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize
* canonical form}.
*/
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
嗯其實是一樣的,GsonType是對TypeToken的核心提取版
簡略說一下我的心得體會:
1)TypeToken要求具體類型,而需求是傳遞抽象類,因此只能仿照寫一個
2)採用抽象類定義,是爲了使用匿名類實現時,使匿名類攜帶具體的類
3)getClass().getSuperclass()獲取的是當前對象所屬的類型的父類型
4) getActualTypeArguments()返回的是確切的類型參數數組, 此處GsonType只有一個類型參數, 返回的是ArrayList[PortIP.class].