Java 和 Ruby 中 JSON 的多态性或继承

发布于 2024-07-16 11:01:03 字数 718 浏览 12 评论 0原文

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

为简单起见,假设我有一个 Pet 类和一个喂养宠物的 FeedPet 进程。 我还有一个进程 WalkDog,仅适用于狗,它是一种宠物。 我的数据经过精心组织,因此我永远不需要担心尝试遛狗以外的宠物。

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

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

我可以创建一个 Dog 扩展 Pet,并且可以使用 Jackson 库将其序列化为 JSON。 JSON 对象将有一个约束字段。 但假设我想喂养所有的宠物。 所有宠物都有一个 getFood() 方法。 因此 FeedPet 进程将对象反序列化为 Pet。 但这就失去了束缚。

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

有什么方法可以将 java 对象序列化为 JSON,以便我可以保留它们的类型吗? 我正在考虑类似 Rails 单表继承的东西,但它必须是 JSON 库能够理解的东西。

For context, we are storing most of our data as JSON strings. This works very well with Hadoop on the backend and is easy to handle in Ruby on the front end. My data types fit the natural pattern for inheritance.

For simplicity, lets say I have a class Pet and a process FeedPet that feeds a pet. I also have a process WalkDog that only applies to Dog, which is a kind of pet. My data is organized such that I never need to worry about trying to walk a pet that isn't a dog.

What I would like to do is have Pet and Dog extends Pet, with Dog having an additional method "getLeash()", but I can't figure out how to map this to JSON.

Instead, I have a class Pet with a species data hashmap, so the WalkDog process would call pet.getSpeciesData("leash") instead of dog.getLeash().

I can create a Dog extends Pet, and I can serialize that to JSON using the Jackson library. The JSON object will have a leash field. But assume that I want to feed all the pets. All pets have a getFood() method. So the FeedPet process deserializes the objects to Pet. But this loses the leash field.

The WalkDog process can do this because it knows all of its input is going to be Dogs, so it can read it as a Dog and write it back out as a Dog.

Is there any way to serialize java objects to JSON such that I can preserve their type? I'm thinking something like Rails single table inheritance, but it would have to be something that the JSON libraries understand.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

遥远的她 2024-07-23 11:01:03

为了使其工作,您必须在数据中嵌入一些对象类型信息(仅对反序列化有用),并且通常使用外部模式定义,否则将不需要(例如用于 xml 的 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);

所以无论如何: Jackson 项目有 执行此操作的功能请求,它允许您做(我认为)您想做的事情。

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

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

To make it work you must both embed some object type information in data (where it is only useful for deserializing) and usually use external schema definition which otherwise would not be needed (like XML Schema for xml; since that's basically a generic type system).
This has same problems as ORM has: Hibernate has to use ugly work-arounds (n+1 - way joins, "super tables" or discriminator fields).

Or another way to put it: data mapping/binding is not quite the same as object serialization/deserialization (latter tries to preserve more of object identity).

Here I am assuming that what you want is basically something like:

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

If this is not the case, you could just simply bind to Dog

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

So anyway: Jackson project has feature request for doing just this, which allow you to do what (I think) you want.

However, this solution will mostly work for Java, as there is no standard way of passing Object type info within JSON. With XML this can sort of be done with XML Schema defined "xsi:type" attribute; which identifies Schema type, which is then mapped to class (yes, rather complicated way, but it does work).

UPDATE: Jackson 1.5 added support for this (i.e. implemented JACKSON-91 feature request), so it can be used for generating type identifiers, to allow proper handling of polymorphic types. It should work with non-Java systems too, given that you can fully configure details of how type information is to be included; and is NOT limited to using Java class names.

还如梦归 2024-07-23 11:01:03

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

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

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

-- 更新

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

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

I've not had that much experience using JSON other than for fixtures in django, but in that instance I just have a "model" key, with the associated value.

It is then up to the program that is interpreting the objects to determine their type and inheritance hierarchy.

What I'm trying to say is that it is irrelevant what methods are available, as this doesn't need to be serialised. Only the object's name and attributes.

-- update

After reading your question again, it seems like your process is deserialising into the parent class, rather than the actual class. Since your dog class inherits from pet, you just want to make sure your deserialiser is creating objects of the most specialised class.

I don't know about the Jackson library, but if you can set it to have a type of model field, then that might be the go.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文