Gson解析泛型的一個小問題

對於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].

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