使用泛型与GSON

时间:2010-11-19 15:57:38

标签: java generics gson

我正在使用GSON将JSON解码为类型为T的对象,例如

public T decode(String json) {
    Gson gson = new Gson();
    return gson.fromJson(json, new TypeToken<T>() {}.getType());
}

然而,这会返回异常 -

java.lang.AssertionError:意外类型。 预期之一: java.lang.reflect.ParameterizedType, java.lang.reflect.GenericArrayType, 但得到:sun.reflect.generics.reflectiveObjects.TypeVariableImpl,用于类型标记:T

我认为通过使用TypeToken,我避免使用Type Erasure。

我错了吗?

由于

3 个答案:

答案 0 :(得分:14)

首先,我没有看到像这样包装Gson是多么有用。

关于您的问题,有关泛型类型T本身的信息在运行时期间不可用。它已被删除。它仅在编译期间可用。您希望使用实际类型对其进行参数化,例如new TypeToken<List<String>>

由于Java中缺少具体的泛型(不可能执行T t = new T()),如您所见,Gson本身被迫使用TypeToken方法。否则Gson会以更优雅的方式完成它。

为了能够传递实际类型,你需要重新发明TypeToken已经在做的事情。这没有任何意义:)只是重复使用它或者直接使用Gson而不将它包装在像这样的辅助类中。

答案 1 :(得分:5)

我认为第一个答案并没有指出实际的解决方案:你还必须和T一起传递Class实例,如下所示:

public T decode(String json, Class<T> cls) {
    Gson gson = new Gson();
    return gson.fromJson(json, cls);
}

这是因为'T'这里是VARIABLE类型,而不是类型引用;并且仅由编译器用于添加隐式转换并验证类型兼容性。但如果你通过实际课程,它可以使用;和编译器将检查类型兼容性,以减少不匹配的可能性。

或者你可以接受TypeToken并传递它;但TypeToken必须使用实数类型而不是类型变量构造;类型变量在这里用处不大。但是如果你想要包装东西,你不希望调用者使用TypeToken(这是一种Gson类型)。

相同的包装机制可以与你提到的像Jackson这样的其他lib一起使用。

答案 2 :(得分:0)

我的解决方案是使用json解析器并将其分解为片段

public static <TT> PushObj<TT> fromJSON(String json, Class<TT> classType)
{
    JsonObject jObj = new JsonParser().parse(json).getAsJsonObject();
    String type = jObj.get("type").getAsString();
    JsonObject job = jObj.get("object").getAsJsonObject();
    TT obj = new Gson().fromJson(job, classType);
    return new PushObj<TT>(type, obj);
}

对象结构是: {String:Type,Generic:Object}

变量是: jObj是传入的字符串的JSONObject 和job是泛型对象的JSONObject

所以我使用json解析器分别获取类型和对象的反射。