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

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