在 Gson 中反序列化抽象类
我有一个 JSON 格式的树对象,我正在尝试使用 Gson 反序列化。每个节点都包含其子节点作为对象类型 Node 的字段。 Node 是一个接口,它有几个具体的类实现。在反序列化过程中,如果我事先不知道节点属于哪种类型,如何与 Gson 通信在反序列化节点时要实现哪个具体类?每个节点都有一个指定类型的成员字段。当对象处于序列化形式时,有没有办法访问该字段,并以某种方式将类型传递给 Gson?
谢谢!
I have a tree object in JSON format I'm trying to deserialize with Gson. Each node contains its child nodes as fields of object type Node. Node is an interface, which has several concrete class implementations. During the deserialization process, how can I communicate to Gson which concrete class to implement when deserializing the node, if I do not know a priori which type the node belongs to? Each Node has a member field specifying the type. Is there a way to access the field when the object is in serialized form, and somehow communicate the type to Gson?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我建议添加自定义 JsonDeserializer for
Node
:您将能够在反序列化器的方法中访问表示节点的
JsonElement
,将其转换为JsonObject< /code>,并检索指定类型的字段。然后,您可以基于此创建正确类型的
Node
实例。I'd suggest adding a custom JsonDeserializer for
Node
s:You will be able to access the
JsonElement
representing the node in the deserializer's method, convert that to aJsonObject
, and retrieve the field that specifies the type. You can then create an instance of the correct type ofNode
based on that.您需要注册 JSONSerializer 和 JSONDeserializer。您还可以通过以下方式为所有接口实现通用适配器:
这是我自己使用的实现并且工作正常。
然后您可以为所有接口注册此适配器,如下所示
You will need to register both JSONSerializer and JSONDeserializer. Also you can implement a generic adapter for all your interfaces in the following way:
Here is the implementation that I have used for myself and works fine.
Then you could register this adapter for all your interfaces as follows
我想稍微纠正一下上面的内容
然后我使用它:
然后我可以将List(我在其中保留一些从Abstract Task继承的非抽象类)解析为Json;
它的作用方向相反
I want to correct the above a little
And then I use it:
And then I can parse List (where I keep some non-abstract classes, which inherited from Abstract Task) to Json;
And it works in the opposite direction
据我所知,这不适用于非集合类型,或者更具体地说,不适用于使用具体类型进行序列化而使用接口类型进行反序列化的情况。也就是说,如果您有一个实现接口的简单类,并且序列化具体类,然后指定要反序列化的接口,那么您最终将陷入不可恢复的情况。
在上面的示例中,类型适配器是针对接口注册的,但是当您使用具体类进行序列化时,它将不会被使用,这意味着 CLASS_META_KEY 数据将永远不会被设置。
如果您将适配器指定为分层适配器(从而告诉 gson 将其用于层次结构中的所有类型),您将最终陷入无限循环,因为序列化程序将继续调用自身。
任何人都知道如何从接口的具体实现进行序列化,然后仅使用接口和 InstanceCreator 进行反序列化?
默认情况下,gson 似乎会创建具体实例,但不会设置它的字段。
问题记录在此处:
http://code. google.com/p/google-gson/issues/detail?id=411&q=interface
As far as I can tell this doesn't work for non-collection types, or more specifically, situations where the concrete type is used to serialize, and the interface type is used to deserialize. That is, if you have a simple class implementing an interface and you serialize the concrete class, then specify the interface to deserialize, you'll end up in an unrecoverable situation.
In the above example the type adapter is registered against the interface, but when you serialize using the concrete class it will not be used, meaning the CLASS_META_KEY data will never be set.
If you specify the adapter as a hierarchical adapter (thereby telling gson to use it for all types in the hierarchy), you'll end up in an infinite loop as the serializer will just keep calling itself.
Anyone know how to serialize from a concrete implementation of an interface, then deserialize using only the interface and an InstanceCreator?
By default it seems that gson will create the concrete instance, but does not set it's fields.
Issue is logged here:
http://code.google.com/p/google-gson/issues/detail?id=411&q=interface
您必须使用 Google Gson 中的
TypeToken
类。当然,您需要一个通用类 T 才能使其正常工作
gson.toJson(foo, fooType);
You have to use
TypeToken
class from Google Gson.You will need of course has a generic class T to make it works
gson.toJson(foo, fooType);
我无法使用上面的 TypeAdapter 解决方案,并且几乎放弃了序列化。最后我在类对象和Gson之间的中间步骤找到了解决方案。我将对象本身序列化为字节数组,然后 Gson 以类似的方式序列化字节数组+反序列化回来。
像这样使用
我希望这可以像帮助我一样帮助别人。
I was unable to use the
TypeAdapter
solutions above, and had almost given up on serializing. In the end I found a solution in an intermediary step between the class object and Gson. I serialized the object itself into a byte array, and then Gson serialized the byte array + deserializing back in similar fashion.Used like this
I'm hoping this might help someone else the way it helped me.