Java Type Generic 作为 GSON 的参数

2022-08-31 15:33:00

在GSON中获取您执行的对象列表

Gson gson = new Gson();
Type token = new TypeToken<List<MyType>>(){}.getType();
return gson.fromJson(json, token);

它工作得很好,但我想更进一步,让MyType参数化,这样我就可以有一个通用函数来解析这个代码的对象列表。

// the common function 
public <T> List<T> fromJSonList(String json, Class<T> type) {
  Gson gson = new Gson();
  Type collectionType = new TypeToken<List<T>>(){}.getType();
  return gson.fromJson(json, collectionType);
}

// the call
List<MyType> myTypes = parser.fromJSonList(jsonString, MyType.class);

可悲的是,返回一个 StringMaps 数组,而不是类型。T 被解释为另一个泛型类型,而不是我的类型。任何解决方法?


答案 1

由于 ,您可以使用 TypeToken#getParametized((Type rawType, Type...typeArguments)) 来创建 ,然后应该做这个把戏。gson 2.8.0typeTokengetType()

例如:

TypeToken.getParameterized(List.class, myType.class).getType();

答案 2

泛型在编译时工作。超类型标记之所以有效,是因为(匿名)内部类可以访问其泛型超类(超接口)的类型参数,而泛型超类(超接口)又直接存储在字节码元数据中。

一旦你.java源文件被编译,type参数显然会被丢弃。由于它在编译时是未知的,因此它不能存储在字节码中,因此它被擦除并且Gson无法读取它。<T>

更新

在newacct的答案之后,我试图实现他在选项2中建议的内容,即实现.代码如下所示(这是一个基本测试):ParameterizedType

class ListOfSomething<X> implements ParameterizedType {

    private Class<?> wrapped;

    public ListOfSomething(Class<X> wrapped) {
        this.wrapped = wrapped;
    }

    public Type[] getActualTypeArguments() {
        return new Type[] {wrapped};
    }

    public Type getRawType() {
        return List.class;
    }

    public Type getOwnerType() {
        return null;
    }

}

此代码的目的是在内部使用:getFromJsonList()

public List<T> fromJsonList(String json, Class<T> klass) {
    Gson gson = new Gson();
    return gson.fromJson(json, new ListOfSomething<T>(klass));
}

即使这项技术有效并且确实非常聪明(我不知道它,我永远不会想到它),这是最终的成就:

List<Integer> list = new Factory<Integer>()
         .getFromJsonList(text, Integer.class)

而不是

List<Integer> list = new Gson().fromJson(text,
         new TypeToken<List<Integer>>(){}.getType());

对我来说,所有这些包装都是无用的,即使我同意这使得代码看起来很讨厌:PTypeToken


推荐