61

在 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 被解释为另一种泛型类型,而不是我的类型。任何解决方法?

4

13 回答 13

57

既然gson 2.8.0,您可以使用TypeToken#getParametized((Type rawType, Type... typeArguments))创建typeToken,那么getType()应该可以解决问题。

例如:

TypeToken.getParameterized(List.class, myType).getType();
于 2017-06-01T09:39:02.317 回答
41

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

一旦你的 .java 源文件被编译, type 参数<T>显然被丢弃了。由于在编译时是不知道的,所以不能存储在字节码中,所以被擦除了,Gson 也无法读取。

更新

在 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());

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

于 2013-01-03T13:17:05.043 回答
29
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);
}

例子:

getList(MyClass[].class, "[{...}]");
于 2015-03-02T08:12:20.813 回答
11

这是来自@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);
}

使用

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

希望有帮助

于 2018-08-21T09:01:20.100 回答
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;
    }

}
于 2015-03-11T09:27:37.513 回答
5

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

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

并像使用它一样

val myTypes: List<MyType> = fromJson(jsonString);

它将解析任何对象,包括 gereric 类型为 List。关键字inlinereified确保该类型不会被删除。

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

于 2020-02-27T13:41:43.570 回答
3

这已在前面的问题中得到解答。基本上,有两种选择:

  1. 从调用站点传入Type。调用代码将使用TypeToken或构建它。
  2. 自己构造一个Type对应于参数化类型的。这将要求您编写一个实现的类ParameterizedType
于 2013-01-03T19:53:31.410 回答
3

如果用 kotlin 编程,我们可以使用reified type parameterinline 函数

class GenericGson {

    companion object {
        inline fun <reified T : Any> Gson.fromJsonTokenType(jsonString: String): T {
            val type = object : TypeToken<T>() {}.type
            return this.fromJson(jsonString, type)
        }

        inline fun <reified T : Any> Gson.fromJsonType(jsonString: String): T = this.fromJson(jsonString, T::class.java)

        inline fun <reified T : Any> fromJsonTokenType(jsonString: String): T = Gson().fromJsonTokenType(jsonString)

        inline fun <reified T : Any> fromJsonType(jsonString: String): T = Gson().fromJsonType(jsonString)
    }
}

并在您的代码中使用如下

val arrayList = GenericGson.fromJsonTokenType<ArrayList<Person>>(json)
于 2017-12-28T11:23:32.817 回答
0

在 kotlin 中简单使用例如:

获取地点功能

fun getPlaces<T> (jsonString : String, clazz: Class<T>) : T { val places : T = Gson().fromJson(jsonString,clazz) return places }

然后你可以用作:

val places = getPlaces(Array<Place>::class.java)
于 2018-07-08T16:18:54.863 回答
0

这适用于一切。例如具有通用键和值的映射。

CustomType type = new CustomType(Map.class, String.class, Integer.class);

所以没有更多的 TokenType。

class CustomType implements ParameterizedType {
    private final Class<?> container;
    private final Class<?>[] wrapped;

    @Contract(pure = true)
    public CustomType(Class<?> container, Class<?>... wrapped) {
        this.container = container;
        this.wrapped = wrapped;
    }

    @Override
    public Type[] getActualTypeArguments() {
        return this.wrapped;
    }

    @Override
    public Type getRawType() {
        return this.container;
    }

    @Override
    public Type getOwnerType() {
        return null;
    }
}
于 2019-10-13T17:13:53.700 回答
0

对我有用的 Kotlin“ListOfSomething”解决方案:

fun <T: Any> getGsonList(json: String, kclass: KClass<T>) : List<T> {

    return getGsonInstance().fromJson<List<T>>(json, ListOfSomething<T>(kclass.java))
}


internal class ListOfSomething<X>(wrapped: Class<X>) : ParameterizedType {

    private val wrapped: Class<*>

    init {
        this.wrapped = wrapped
    }

    override fun getActualTypeArguments(): Array<Type> {
        return arrayOf<Type>(wrapped)
    }

    override fun getRawType(): Type {
        return ArrayList::class.java
    }

    override fun getOwnerType(): Type? {
        return null
    }
}
于 2017-06-19T14:32:38.787 回答
0
  public static <T> T getObject(String gsonStr) {
        Gson gson = new GsonBuilder()
                .setLenient()
                .create();
        Type collectionType = new TypeToken< T>(){}.getType();
        return gson.fromJson(gsonStr,
                collectionType);
    }

使用时:

Class1 class1=  getObject(jsonStr);
于 2019-05-20T16:56:06.350 回答
0
public <T> List<T> fromJSonList(String json) {
  Gson gson = new Gson();
  Type collectionType = new TypeToken<List<T>>(){}.getType();
  return gson.fromJson(json, collectionType);
}

//Just call
List<MyType> myTypes = parser.<MyType>fromJSonList(jsonString);
于 2020-06-23T04:07:12.270 回答