使用泛型与GSON

chr*_*ann 21 java generics gson

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

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

然而,这会返回一个例外 -

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

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

我错了吗?

谢谢

Bal*_*usC 14

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

至于您的问题,有关泛型类型T本身的信息在运行时期间不可用.它已被删除.它仅在编译期间可用.你想用实际的类型来参数化它new TypeToken<List<String>>.

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

为了能够传递实际类型,你需要重新发明和现在一样的东西TypeToken.这没有任何意义:)只是重复使用它或只是直接使用Gson而不将它包装在像这样的辅助类中.

  • 你最好的办法是重用Gson的`TypeToken`作为类或方法参数,或者至少要重新发明它,如果你不想在你的API中公开第三方依赖.[这是Apache许可证的开源](http://code.google.com/p/google-gson/source/browse/trunk/src/main/java/com/google/gson/reflect/TypeToken.java?spec = svn2&R = 2).[此处提供背景说明](http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener). (3认同)

Sta*_*Man 5

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

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

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

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

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

  • 这不适用于这个问题的参数化类.没有像Map <String,Object> .class`这样的东西,只有`Map.class`.另请参阅我的答案中的评论中的"背景说明"链接. (4认同)