简体   繁体   English

从 POJO 到 vertx.io 的 JsonObject 的优雅映射?

[英]Elegant mapping from POJOs to vertx.io's JsonObject?

I am currently working on a vertx.io application and wanted to use the provide mongo api for data storage.我目前正在开发一个vertx.io应用程序,并希望使用提供的 mongo api 进行数据存储。 I currently have a rather clunky abstraction on top of the stock JsonObject classes where all get and set methods are replaced with things like:我目前在股票 JsonObject 类之上有一个相当笨重的抽象,其中所有getset方法都被替换为以下内容:

this.backingObject.get(KEY_FOR_THIS_PROPERTY);

This is all well and good for now, but it won't scale particularly well.现在这一切都很好,但它不会扩展得特别好。 it also seems dirty, specifically when using nested arrays or objects.它看起来也很脏,特别是在使用嵌套数组或对象时。 For example, if I want to be able to fill fields only when actual data is known, I have to check if the array exists, and if it doesn't create it and store it in the object.例如,如果我希望仅在已知实际数据时才能够填充字段,则必须检查数组是否存在,以及是否不创建它并将其存储在对象中。 Then I can add an element to the list.然后我可以向列表中添加一个元素。 For example:例如:

if (this.backingObject.getJsonArray(KEY_LIST) == null) {
    this.backingObject.put(KEY_LIST, new JsonArray());
}
this.backingObject.getJsonArray(KEY_LIST).add(p.getBackingObject());

I have thought about potential solutions but don't particularly like any of them.我已经考虑过潜在的解决方案,但并不特别喜欢其中的任何一个。 Namely, I could use Gson or some similar library with annotation support to handle loading the object for the purposes of manipulating the data in my code, and then using the serialize and unserialize function of both Gson and Vertx to convert between the formats (vertx to load data -> json string -> gson to parse json into pojos -> make changes -> serialize to json string -> parse with vertx and save) but that's a really gross and inefficient workflow.也就是说,我可以使用 Gson 或一些具有注释支持的类似库来处理加载对象,以便在我的代码中操作数据,然后使用 Gson 和 Vertx 的序列化和反序列化功能在格式(vertx to load data -> json string -> gson to parse json into pojos -> make changes -> serialize to json string -> parse with vertx and save)但这是一个非常(vertx to load data -> json string -> gson to parse json into pojos -> make changes -> serialize to json string -> parse with vertx and save)且效率低下的工作流程。 I could also probably come up with some sort of abstract wrapper that extends/implements the vertx json library but passes all the functionality through to gson, but that also seems like a lot of work.我也可能想出某种抽象包装器来扩展/实现 vertx json 库,但将所有功能传递给 gson,但这似乎也需要做很多工作。

Is there any good way to achieve more friendly and maintainable serialization using vertx?有什么好方法可以使用vertx实现更友好和可维护的序列化吗?

I just submitted a patch to Vert.x that defines two new convenience functions for converting between JsonObject and Java object instances without the inefficiency of going through an intermediate JSON string representation.我刚刚向 Vert.x 提交了一个补丁,该补丁定义了两个新的便捷函数,用于在 JsonObject 和 Java 对象实例之间进行转换,而不会通过中间 JSON 字符串表示而效率低下。 This will be in version 3.4.这将在 3.4 版中。

// Create a JsonObject from the fields of a Java object.
// Faster than calling `new JsonObject(Json.encode(obj))`.
public static JsonObject mapFrom(Object obj)

// Instantiate a Java object from a JsonObject.
// Faster than calling `Json.decodeValue(Json.encode(jsonObject), type)`.
public <T> T mapTo(Class<T> type)

Internally this uses ObjectMapper#convertValue(...) , see Tim Putnam's answer for caveats of this approach.这在内部使用ObjectMapper#convertValue(...) ,请参阅 Tim Putnam 的回答以了解此方法的注意事项。 The code is here .代码在这里

Not sure if I've understood you correctly, but it sounds like you're trying to find a simple way of converting POJOs to JsonObject?不确定我是否理解正确,但听起来您正在尝试找到一种将 POJO 转换为 JsonObject 的简单方法?

So, we have lots of pojos that we send over the EventBus as JsonObject s所以,我们有很多EventBus作为JsonObject s 通过EventBus发送

I've found the easiest way is to use the vert.x Json class which has loads of helper methods to convert to / from Json Strings我发现最简单的方法是使用vert.x Json类,它有大量的辅助方法来转换为/从Json Strings

JsonObject jsonObject = new JsonObject(Json.encode(myPojo));

Sometimes you need to add some custom (de)serializers, but we always stick with Jackson - that is what Vert.x is using so they work out of the box.有时您需要添加一些自定义(反)序列化器,但我们始终坚持使用Jackson - 这就是Vert.x正在使用的,因此它们开箱即用。

What we actually do, is provide an interface like the following:我们实际做的是提供一个如下所示的接口:

public JsonObjectSerializable {
    public JsonObject toJson();
}

And all our pojos that need to be sent over the EventBus have to implement this interface.我们所有需要通过EventBus发送的EventBus都必须实现这个接口。

Then our EventBus sending code looks something like (simplified):然后我们的EventBus发送代码看起来像(简化):

public <T extends JsonObjectSerializable> Response<T> dispatch(T eventPayload);

Also, as we generally don't unit test Pojos, adding this interface encourages the developers to unit test their conversion.此外,由于我们通常不对 Pojos 进行单元测试,因此添加此interface鼓励开发人员对他们的转换进行单元测试。

Hope this helps,希望这可以帮助,

Will将要

I believe Jackson's ObjectMapper.convertValue(..) functions don't convert via String, and Vert.x is using Jackson for managing JsonObject anyway.我相信 Jackson 的ObjectMapper.convertValue(..)函数不会通过 String 进行转换,而 Vert.x 无论如何都使用 Jackson 来管理 JsonObject。

JsonObject just has an underlying map representing the values, accessible via JsonObject.getMap() , and a Jackson serializer/deserializer on the public ObjectMapper instance in io.vertx.core.json.Json. JsonObject只有一个表示值的底层映射,可通过JsonObject.getMap()访问,以及 io.vertx.core.json.Json 中公共ObjectMapper实例上的 Jackson 序列化器/反序列化器。

To switch between JsonObject and a data model expressed in Pojos serializable with Jackson, you can do:要在JsonObject和用可与 Jackson 序列化的 Pojos 表示的数据模型之间切换,您可以执行以下操作:

JsonObject myVertxMsg = ... MyPojo pojo = Json.mapper.convertValue ( myVertxMsg.getMap(), MyPojo.class );

I would guess this is more efficient than going via a String (but its just a guess), and I hate the idea of altering the data class just to suit the environment, so it depends on the context - form vs performance.我猜这比通过字符串更有效(但它只是一个猜测),而且我讨厌改变数据类以适应环境的想法,因此它取决于上下文 - 形式与性能。

To convert from Pojo to JsonObject , convert to a map with Jackson and then use the constructor on JsonObject :要将 Pojo 转换为JsonObject ,请使用 Jackson 转换为映射,然后在JsonObject上使用构造函数:

JsonObject myobj = new JsonObject ( Json.mapper.convertValue ( pojo, Map.class ));

  • If you have implied nested JsonObjects or JsonArray objects in your definition, they will get instantiated as Maps and Lists by default.如果您在定义中隐含了嵌套的 JsonObjects 或 JsonArray 对象,默认情况下它们将被实例化为 Maps 和 Lists。 JsonObject will internally re-wrap these when you access fields specifying those types (eg with getJsonArray(..).当您访问指定这些类型的字段(例如使用 getJsonArray(..) 时,JsonObject 将在内部重新包装它们。

  • Because JsonObject is freeform and you're converting to a static type, you may get some unwanted UnrecognizedPropertyException to deal with.因为 JsonObject 是自由格式并且您正在转换为静态类型,所以您可能会遇到一些不需要的 UnrecognizedPropertyException 来处理。 It may be useful to create your own ObjectMapper, add the vertx JsonObjectSerializer and JsonArraySerializer, and then make configuration changes to suit (such as DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES in Jackson).创建自己的 ObjectMapper,添加 vertx JsonObjectSerializer 和 JsonArraySerializer,然后进行配置更改以适应(例如 Jackson 中的DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES )可能会很有用。

尝试这个:

io.vertx.core.json.Json.mapper.convertValue(json.getMap(), cls)

I think that using Gson as you described is the best possible solution at the current time.我认为使用您描述的 Gson 是目前最好的解决方案。

While I agree that if a protocol layer was included in Vert.x it would indeed be first prize, using Gson keeps your server internals pretty organised and is unlikely to be the performance bottleneck.虽然我同意如果 Vert.x 中包含协议层,它确实会是一等奖,但使用 Gson 可以使您的服务器内部结构井井有条,并且不太可能成为性能瓶颈。

When and only when this strategy becomes the performance bottleneck have you reached the point to engineer a better solution.当且仅当此策略成为性能瓶颈时,您才能设计出更好的解决方案。 Anything before that is premature optimisation.在此之前的任何事情都是过早的优化。

My two cents.我的两分钱。

你可以试试:

new JsonObject().mapFrom(object)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM