我看过许多其他类似的问题,但我认为在这些问题上有一定程度的抽象。即,我有一个带有静态通用包装器方法的实用工具类,用于反序列化通用类型的对象(在构建时未知):
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());
}
}
一个简单的类对其进行测试:
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);
但是,尽管静态通用实用程序方法没有,但看上去却是等效的调用方式:
assertEquals(
new TestDocument("test").test,
Utils.<TestDocument>fromJson("{\"test\": \"test\"}").test);
引发以下异常:
java.lang.ClassCastException:com.google.gson.internal.LinkedTreeMap 无法转换为TestDocument
有没有办法使它通过通用方法工作?
答案 0 :(得分:1)
如果可能的话,Gson
可能已经添加了此方法,并且看起来像这样:
TestDocument document = gson.<TestDocument>fromJson(json);
具有此签名的方法:
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException
已包含JavaDoc
:
此方法将指定的Json反序列化为 指定的类别。如果指定的类是A,则不适合使用 通用类型,因为它将没有通用类型信息 由于 Java的类型清除功能。因此,这种方法 如果所需类型是泛型类型,则不应使用。注意 如果指定的任何字段都可以使用此方法 对象是泛型的,只是对象本身不应该是泛型的 类型。对于对象为通用类型的情况,请调用
fromJson(String, Type)
。如果您在Reader
中使用Json而不是String
,请使用fromJson(Reader, Class)
。
第二个参数名称为classOfT
的含义为the class of T
。
答案 1 :(得分:1)
有一些类型用法提示:
<T>
而不传递实际类型是一个骗局。Class<T>
传递不是一个好主意,因为###.class
仅表示JVM加载的类(原始类型除外)。这样,Class<List<String>>
和Class<List<Map<Integer, ?>>>
完全一样,List.class
失去了类型参数设置,因此在不考虑适当类型的情况下使Gson(反)序列化工作(例如,LinkedHashTreeMap是一个很好的例子,如果我记得)。Type
一起使用,它是Java类型系统可以表示的任何类型(包括类,ParameterizedType
等)的超类型接口。参见https://google.github.io/gson/apidocs/com/google/gson/Gson.html#fromJson-java.lang.String-java.lang.reflect.Type- TypeToken
是Java中通用类型持有者的一个很好的例子,其中包括根据其生成方式产生适当的类型信息。它可以使您的方法类型安全:public static <T> T fromJson(String doc, TypeToken<? extends T> typeToken) { return sGson.fromJson(doc, typeToken.getType()); }
。类型令牌可以被缓存到具有实际参数化功能的公共(是)静态最终字段中,因为它们在线程之间是不可变的并且是线程安全的。奖金:
synchronized
:Gson
实例也是线程安全的。答案 2 :(得分:0)
在Java中,如果不显式传递实际类型,以致于在构建时就知道它,这是不可能的。
这是一种解决方案:
public static synchronized <T> T fromJson(String doc, Class<T> type) {
return sGson.fromJson(doc, type);
}
然后测试通过:
assertEquals((new TestDocument("test").test), Utils.<TestDocument>fromJson("{\"test\": \"test\"}", TestDocument.class).test);
在这个特定的(故意过分简化)的示例中,这看起来可以用一种更简单,更优雅的方式来完成,但是当它是更大,更复杂的场景的一部分时,它可能是唯一的选择。