Java Type Generic作为GSON的参数

Rod*_*sio 48 java generics gson

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

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

它工作得很好,但我想更进一步,让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);
Run Code Online (Sandbox Code Playgroud)

遗憾地返回一个StringMaps数组,而不是类型.T被解释为另一种泛型类型,而不是我的类型.任何解决方法?

Raf*_*ele 42

泛型在编译时工作.超类型令牌工作的原因是因为(匿名)内部类可以访问其通用超类(超级接口)的类型参数,而这些超类又直接存储在字节码元数据中.

编译完.java源文件后,类型参数<T>显然会被丢弃.由于在编译时不知道它,它不能存储在字节码中,因此它被擦除而Gson无法读取它.

UPDATE

在newacct的回答之后,我尝试实现他在选项2中建议的内容,即实现a 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;
    }

}
Run Code Online (Sandbox Code Playgroud)

这段代码的目的是在里面使用getFromJsonList():

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

即使该技术有效并且确实非常聪明(我不知道它并且我从未想过它),这是最后的成就:

List<Integer> list = new Factory<Integer>()
         .getFromJsonList(text, Integer.class)
Run Code Online (Sandbox Code Playgroud)

代替

List<Integer> list = new Gson().fromJson(text,
         new TypeToken<List<Integer>>(){}.getType());
Run Code Online (Sandbox Code Playgroud)

对我来说,所有这些包装都没用,即使我同意TypeTokens使代码看起来很讨厌:P


old*_*god 34

既然gson 2.8.0,你可以使用TypeToken#getParametized((Type rawType, Type... typeArguments))创建typeToken,那么getType()应该做的伎俩.

例如:

TypeToken.getParameterized(List.class, myType).getType();
Run Code Online (Sandbox Code Playgroud)


kay*_*yz1 28

public static final <T> List<T> getList(final Class<T[]> clazz, final String json)
{
    final T[] jsonToObject = new Gson().fromJson(json, clazz);

    return Arrays.asList(jsonToObject);
}
Run Code Online (Sandbox Code Playgroud)

例:

getList(MyClass[].class, "[{...}]");
Run Code Online (Sandbox Code Playgroud)


Chr*_*ann 6

我已经将Raffaele的方法更进了一步并将该类化为一般化,因此它适用于每个类A,其中B是非参数化类.可能对集合和其他集合有用.

    public class GenericOf<X, Y> implements ParameterizedType {

    private final Class<X> container;
    private final Class<Y> wrapped;

    public GenericOf(Class<X> container, Class<Y> wrapped) {
        this.container = container;
        this.wrapped = wrapped;
    }

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

    public Type getRawType() {
        return container;
    }

    public Type getOwnerType() {
        return null;
    }

}
Run Code Online (Sandbox Code Playgroud)


Pha*_*inh 5

这是完整的代码库,基于@oldergod的出色回答

public <T> List<T> fromJSonList(String json, Class<T> myType) {
    Gson gson = new Gson();
    Type collectionType = TypeToken.getParameterized(List.class, myType).getType();
    return gson.fromJson(json, collectionType);
}
Run Code Online (Sandbox Code Playgroud)

使用

List<MyType> myTypes = parser.fromJSonList(jsonString, MyType.class);
Run Code Online (Sandbox Code Playgroud)

希望对你有帮助


goo*_*ofy 5

Kotlin 中,你可以简单地使用这个函数:

inline fun <reified T> fromJson(json: String): T {
  return Gson().fromJson(json, object: TypeToken<T>(){}.type)
}
Run Code Online (Sandbox Code Playgroud)

并像使用它一样

val myTypes: List<MyType> = fromJson(jsonString);
Run Code Online (Sandbox Code Playgroud)

它将解析任何对象,包括作为列表的 gereric 类型。关键字inlinereified确保类型不会被擦除。

有关详细信息,我可以推荐此Medium 帖子