3

对于上下文,我们将大部分数据存储为 JSON 字符串。这与后端的 Hadoop 配合得非常好,并且在前端的 Ruby 中很容易处理。我的数据类型符合继承的自然模式。

为简单起见,假设我有一个 Pet 类和一个喂宠物的进程 FeedPet。我还有一个进程WalkDog,它只适用于Dog,它是一种宠物。我的数据是经过组织的,因此我永远不必担心试图遛一只不是狗的宠物。

我想做的是让 Pet 和 Dog 扩展 Pet,Dog 有一个额外的方法“getLeash()”,但我不知道如何将它映射到 JSON。

相反,我有一个带有物种数据哈希图的 Pet 类,因此 WalkDog 进程将调用 pet.getSpeciesData("leash") 而不是 dog.getLeash()。

我可以创建一个 Dog extends Pet,并且可以使用 Jackson 库将其序列化为 JSON。JSON 对象将有一个 leash 字段。但假设我想喂饱所有的宠物。所有宠物都有一个 getFood() 方法。因此 FeedPet 进程将对象反序列化为 Pet。但这失去了皮带领域。

WalkDog 进程可以做到这一点,因为它知道它的所有输入都将是 Dog,因此它可以将其作为 Dog 读取并将其作为 Dog 写回。

有什么方法可以将 java 对象序列化为 JSON,以便我可以保留它们的类型?我在想像 Rails 单表继承这样的东西,但它必须是 JSON 库可以理解的东西。

4

2 回答 2

2

要使其工作,您必须在数据中嵌入一些对象类型信息(它仅对反序列化有用),并且通常使用否则不需要的外部模式定义(如 XML Schema for xml;因为这基本上是一个通用类型系统) . 这与 ORM 有相同的问题:Hibernate 必须使用丑陋的解决方法(n+1 - 方式连接、“超级表”或鉴别器字段)。

或者换一种说法:数据映射/绑定与对象序列化/反序列化并不完全相同(后者试图保留更多的对象标识)。

在这里,我假设您想要的基本上是:

Pet pet = mapper.readValue(jsonString, Pet.class);
// (and possibly get an exception if Pet is an abstract class...)
Leash l = ((Dog) pet).getLeash();

如果不是这种情况,您可以简单地绑定到 Dog

Dog dog = mapper.readValue(jsonString, Dog.class);

所以无论如何:杰克逊项目有做这个的功能请求,它允许你做你想做的(我认为)。

然而,这个解决方案主要适用于 Java,因为在 JSON 中没有标准的传递对象类型信息的方法。对于 XML,这可以通过 XML Schema 定义的“xsi:type”属性来完成;它标识 Schema 类型,然后将其映射到类(是的,相当复杂的方式,但它确实有效)。

更新Jackson 1.5添加了对此的支持(即实现了 JACKSON-91 功能请求),因此它可以用于生成类型标识符,以允许正确处理多态类型。它也应该适用于非 Java 系统,因为您可以完全配置如何包含类型信息的详细信息;并且不限于使用 Java 类名。

于 2009-04-08T20:26:23.080 回答
0

除了 django 中的固定装置之外,我没有太多使用 JSON 的经验,但在那种情况下,我只有一个“模型”键,以及相关的值。

然后由解释对象的程序来确定它们的类型和继承层次结构。

我想说的是,可用的方法无关紧要,因为这不需要序列化。只有对象的名称和属性。

- 更新

再次阅读您的问题后,您的进程似乎正在反序列化为父类,而不是实际的类。由于您的 dog 类继承自 pet,您只想确保您的反序列化器正在创建最专业的类的对象。

我不了解 Jackson 库,但如果您可以将其设置为具有一种模型字段,那么可能就是这样。

于 2009-04-08T00:24:27.200 回答