将泛型与 GSON 结合使用

2022-09-02 01:46:08

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

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

但是,这将返回一个异常 -

java.lang.AssertionError: Unexpected type.预期的一个: java.lang.reflect.ParameterizedType, java.lang.reflect.GenericArrayType, 但得到: sun.reflect.generics.reflectiveObjects.TypeVariableImpl, for type token: T

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

我错了吗?

谢谢


答案 1

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

至于您的问题,有关泛型类型本身的信息在运行时不可用。它已被删除。它仅在编译时可用。您希望使用实际类型而不是像 .Tnew TypeToken<List<String>>

由于Java中缺乏重新定义的泛型(不可能做一个),Gson本身被迫使用这种方法,如您所见。否则,Gson会以一种更优雅的方式做到这一点。T t = new T()TypeToken

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


答案 2

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

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

这是因为这里的“T”是一个类型变量,而不是一个类型引用;并且仅由编译器用于添加隐式强制转换和验证类型兼容性。但是如果你传递实际的类,它可以被使用;编译器将检查类型兼容性,以减少不匹配的机会。

或者,您可以接受TypeToken并通过它;但是TypeToken必须用实数类型构造,而不是类型变量;类型变量在这里用处不大。但是,如果您确实想包装内容,则不希望调用方使用TypeToken(这是Gson类型)。

同样的包装机制也适用于其他库,比如你提到的Jackson。


推荐