Java Type Generic作为GSON的参数

时间:2013-01-03 12:58:54

标签: java generics gson

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

13 个答案:

答案 0 :(得分:42)

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

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

<强>更新

在newacct的回答之后,我试图实现他在选项2中建议的内容,即实现ParameterizedType。代码看起来像这样(这是一个基本的test):

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

答案 1 :(得分:29)

Screen开始,您可以使用TypeToken#getParametized((Type rawType, Type... typeArguments))创建gson 2.8.0,然后typeToken就可以了。

例如:

getType()

答案 2 :(得分:27)

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, "[{...}]");

答案 3 :(得分:6)

我已经采取Raffaele's方法更进一步并且对类进行了整合,因此它适用于每个类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;
    }

}

答案 4 :(得分:4)

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

希望有帮助

答案 5 :(得分:3)

以前的问题已经回答了这个问题。基本上,有两个选项:

  1. 从调用网站传递Type。调用代码将使用TypeToken或其他任何内容构建它。
  2. 自己构建与参数化类型对应的Type。这将要求您编写一个实现ParameterizedType
  3. 的类

答案 6 :(得分:3)

科特林中,您可以简单地使用此功能:

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 post

答案 7 :(得分:2)

如果在kotlin中编程,我们可以在内联函数中使用reified type parameter

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)

答案 8 :(得分: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
    }
}

答案 9 :(得分: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)

答案 10 :(得分: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);

答案 11 :(得分: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;
    }
}

答案 12 :(得分: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);