22

我正在使用 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。

我错了吗?

谢谢

4

3 回答 3

14

首先,我看不出像这样包装 Gson 有什么用处。

至于您的问题,有关泛型类型T本身的信息在运行时不可用。它已被抹去。它仅在编译期间可用。您想使用实际类型对其进行参数化,而不是像new TypeToken<List<String>>.

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

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

于 2010-11-19T16:43:00.753 回答
5

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

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

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

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

相同的包装机制适用于您提到的其他库,例如 Jackson。

于 2011-01-04T18:42:42.400 回答
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 解析器分别获取类型和对象的反射。

于 2016-01-25T01:29:27.640 回答