如何通过静态实用程序方法正确使用Gson反序列化通用类型的对象? [英] How correctly use Gson to deserialize an object of generic type through a static utility method?
问题描述
我已经看到了许多其他相似的问题,但是我认为在这些问题上有一定程度的抽象.即,我有一个带有静态通用包装器方法的实用程序类,用于反序列化通用类型的对象(在构建时未知):
I've seen a number of other similar looking questions, but I think there's a level of abstraction on top of those that makes the difference. Namely, I have a utility class with a static generic wrapper method to deserialize an object of generic type (unknown at build time):
public final class Utils {
public static final Gson sGson = new Gson();
public static synchronized <T> T fromJson(String doc) {
return sGson.fromJson(doc, new TypeToken<T>(){}.getType());
}
}
一个简单的类对其进行测试:
A simple class to test it on:
public class TestDocument {
public TestDocument(String test) {
this.test = test;
}
public String test;
}
效果很好:
assertEquals(
new TestDocument("test").test,
((TestDocument) Utils.sGson.fromJson(
"{\"test\": \"test\"}",
new TypeToken<TestDocument>(){}.getType())).test);
但是,尽管静态通用实用程序方法没有,但看上去却是等效的调用方式:
But what looks like an equivalent way to call this though the static generic utility method does not:
assertEquals(
new TestDocument("test").test,
Utils.<TestDocument>fromJson("{\"test\": \"test\"}").test);
引发以下异常:
java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap无法转换为TestDocument
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to TestDocument
有没有办法让它通过通用方法工作?
Is there a way to make it work through the generic method?
推荐答案
有一些类型用法提示:
- 使用
< T>
而不传递实际类型是一个骗局,由于泛型类型擦除. - 将类型作为
Class< T>
传递不是一个好主意,因为###.class
仅表示JVM加载的类(原始类型除外)..这样,Class< List< String>>
和Class< List< Map< Integer,?>>>
完全相同.class 丢失类型参数,因此使Gson(反)序列化工作时无需考虑适当的类型(例如,如果我记得,LinkedHashTreeMap是一个很好的例子). - Gson通常与
Type
一起使用,该类型是Java类型系统可以表示的任何类型(包括类,ParameterizedType
等)的超类型接口.请参见
- Using
<T>
without passing an actual type is a hoax due to the generic types erasure. - Passing the type as
Class<T>
is not a very good idea because###.class
merely represents a class loaded by JVM (except the primitive types). Having that,Class<List<String>>
andClass<List<Map<Integer, ?>>>
are totally the sameList.class
losing type parameterization therefore making Gson (de)serialize work without proper types in mind (LinkedHashTreeMap, for example, is a good example if I remember). - Gson mostly works with
Type
that is a super type interface for any type that can be represented by the Java type system (including classes,ParameterizedType
, etc). See https://google.github.io/gson/apidocs/com/google/gson/Gson.html#fromJson-java.lang.String-java.lang.reflect.Type- TypeToken
is a good example of a generic type holder in Java, including it produces proper type information depending on how it was build. It can be used to make your method type safe:public static <T> T fromJson(String doc, TypeToken<? extends T> typeToken) { return sGson.fromJson(doc, typeToken.getType()); }
. Type tokens can be cached into public (yes) static final fields holding real parameterization due being immutable and thread-safe across threads.
奖金:
- 在那里不需要
同步
:Gson
实例也是线程安全的.
- No
synchronized
is necessary there:Gson
instances are thread-safe too.
这篇关于如何通过静态实用程序方法正确使用Gson反序列化通用类型的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!