我有一个 JSON 格式的树对象,我正在尝试用 Gson 反序列化。每个节点都包含其子节点作为对象类型节点的字段。Node 是一个接口,它有几个具体的类实现。在反序列化过程中,如果我不知道节点属于哪种类型,我如何与 Gson 通信在反序列化节点时要实现哪个具体类?每个节点都有一个指定类型的成员字段。当对象处于序列化形式时,有没有办法访问该字段,并以某种方式将类型传达给 Gson?
谢谢!
我有一个 JSON 格式的树对象,我正在尝试用 Gson 反序列化。每个节点都包含其子节点作为对象类型节点的字段。Node 是一个接口,它有几个具体的类实现。在反序列化过程中,如果我不知道节点属于哪种类型,我如何与 Gson 通信在反序列化节点时要实现哪个具体类?每个节点都有一个指定类型的成员字段。当对象处于序列化形式时,有没有办法访问该字段,并以某种方式将类型传达给 Gson?
谢谢!
我建议为s 添加一个自定义JsonDeserializerNode
:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Node.class, new NodeDeserializer())
.create();
您将能够JsonElement
在反序列化器的方法中访问表示节点,将其转换为 a JsonObject
,并检索指定类型的字段。然后,您可以Node
基于此创建正确类型的实例。
您将需要注册 JSONSerializer 和 JSONDeserializer。您还可以通过以下方式为所有接口实现通用适配器:
这是我自己使用的实现并且工作正常。
public class PropertyBasedInterfaceMarshal implements
JsonSerializer<Object>, JsonDeserializer<Object> {
private static final String CLASS_META_KEY = "CLASS_META_KEY";
@Override
public Object deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext)
throws JsonParseException {
JsonObject jsonObj = jsonElement.getAsJsonObject();
String className = jsonObj.get(CLASS_META_KEY).getAsString();
try {
Class<?> clz = Class.forName(className);
return jsonDeserializationContext.deserialize(jsonElement, clz);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
@Override
public JsonElement serialize(Object object, Type type,
JsonSerializationContext jsonSerializationContext) {
JsonElement jsonEle = jsonSerializationContext.serialize(object, object.getClass());
jsonEle.getAsJsonObject().addProperty(CLASS_META_KEY,
object.getClass().getCanonicalName());
return jsonEle;
}
}
然后你可以为你的所有接口注册这个适配器,如下所示
Gson gson = new GsonBuilder()
.registerTypeAdapter(IInterfaceOne.class,
new PropertyBasedInterfaceMarshal())
.registerTypeAdapter(IInterfaceTwo.class,
new PropertyBasedInterfaceMarshal()).create();
据我所知,这不适用于非集合类型,或者更具体地说,不适用于具体类型用于序列化而接口类型用于反序列化的情况。也就是说,如果您有一个实现接口的简单类并且您序列化具体类,然后指定要反序列化的接口,您最终将处于不可恢复的境地。
在上面的示例中,类型适配器是针对接口注册的,但是当您使用具体类进行序列化时,它将不会被使用,这意味着永远不会设置 CLASS_META_KEY 数据。
如果您将适配器指定为分层适配器(从而告诉 gson 将其用于层次结构中的所有类型),您将进入无限循环,因为序列化程序将继续调用自己。
任何人都知道如何从接口的具体实现序列化,然后仅使用接口和 InstanceCreator 反序列化?
默认情况下,gson 似乎会创建具体实例,但不会设置它的字段。
问题记录在这里:
http://code.google.com/p/google-gson/issues/detail?id=411&q=interface
您必须使用TypeToken
Google Gson 的课程。您当然需要一个通用类 T 才能使其正常工作
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo, fooType);
gson.fromJson(json, fooType);