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

时间:2021-07-12 18:03:26

I am currently working on a vertx.io application and wanted to use the provide mongo api for data storage. 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:

我目前正在研究vertx.io应用程序,并希望使用提供的mongo api进行数据存储。我目前在库存JsonObject类之上有一个相当笨重的抽象,其中所有get和set方法都替换为:

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. 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.

我曾考虑过潜在的解决方案,但并不特别喜欢它们。也就是说,我可以使用Gson或一些带有注释支持的类似库来处理加载对象以便在我的代码中操作数据,然后使用Gson和Vertx的序列化和反序列化函数来转换格式(vertx到加载数据 - > json string - > gson将json解析为pojos - > make changes - > serialize to json string - >使用vertx解析并保存)但这是一个非常粗糙和低效的工作流程。我也可能想出一些扩展/实现vertx json库的抽象包装器,但是将所有功能传递给gson,但这看起来似乎也很多。

Is there any good way to achieve more friendly and maintainable serialization using vertx?

有没有什么好方法可以使用vertx实现更友好和可维护的序列化?

5 个解决方案

#1


16  

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. This will be in version 3.4.

我刚刚向Vert.x提交了一个补丁,它定义了两个新的便捷函数,用于在JsonObject和Java对象实例之间进行转换,而不会经历中间JSON字符串表示的低效率。这将是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. The code is here.

在内部,它使用ObjectMapper#convertValue(...),请参阅Tim Putnam对这种方法的警告的回答。代码在这里。

#2


8  

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 JsonObjects

所以,我们有很多pojos,我们通过EventBus作为JsonObjects发送

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 /从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.

有时您需要添加一些自定义(de)序列化程序,但我们始终坚持使用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发送的所有pojos都必须实现此接口。

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进行单元测试,因此添加此接口可鼓励开发人员对其转换进行单元测试。

Hope this helps,

希望这可以帮助,

Will

#3


5  

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 );

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.

我猜这比通过String更有效(但它只是一个猜测),我讨厌改变数据类只是为了适应环境的想法,所以它取决于上下文 - 形式与性能。

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 ));

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. JsonObject will internally re-wrap these when you access fields specifying those types (e.g. with getJsonArray(..).

    如果您在定义中隐含了嵌套的JsonObjects或JsonArray对象,则默认情况下它们将被实例化为Maps和Lists。当您访问指定这些类型的字段时,JsonObject将在内部重新包装这些类型(例如,使用getJsonArray(..))。

  • Because JsonObject is freeform and you're converting to a static type, you may get some unwanted UnrecognizedPropertyException to deal with. 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).

    因为JsonObject是*形式的并且您正在转换为静态类型,所以您可能会遇到一些不需要的UnrecognizedPropertyException来处理。创建自己的ObjectMapper,添加vertx JsonObjectSerializer和JsonArraySerializer,然后进行配置更改(例如Jackson中的DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)可能很有用。

#4


0  

Try this:

尝试这个:

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

#5


0  

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.

我的两分钱。

#1


16  

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. This will be in version 3.4.

我刚刚向Vert.x提交了一个补丁,它定义了两个新的便捷函数,用于在JsonObject和Java对象实例之间进行转换,而不会经历中间JSON字符串表示的低效率。这将是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. The code is here.

在内部,它使用ObjectMapper#convertValue(...),请参阅Tim Putnam对这种方法的警告的回答。代码在这里。

#2


8  

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 JsonObjects

所以,我们有很多pojos,我们通过EventBus作为JsonObjects发送

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 /从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.

有时您需要添加一些自定义(de)序列化程序,但我们始终坚持使用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发送的所有pojos都必须实现此接口。

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进行单元测试,因此添加此接口可鼓励开发人员对其转换进行单元测试。

Hope this helps,

希望这可以帮助,

Will

#3


5  

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 );

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.

我猜这比通过String更有效(但它只是一个猜测),我讨厌改变数据类只是为了适应环境的想法,所以它取决于上下文 - 形式与性能。

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 ));

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. JsonObject will internally re-wrap these when you access fields specifying those types (e.g. with getJsonArray(..).

    如果您在定义中隐含了嵌套的JsonObjects或JsonArray对象,则默认情况下它们将被实例化为Maps和Lists。当您访问指定这些类型的字段时,JsonObject将在内部重新包装这些类型(例如,使用getJsonArray(..))。

  • Because JsonObject is freeform and you're converting to a static type, you may get some unwanted UnrecognizedPropertyException to deal with. 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).

    因为JsonObject是*形式的并且您正在转换为静态类型,所以您可能会遇到一些不需要的UnrecognizedPropertyException来处理。创建自己的ObjectMapper,添加vertx JsonObjectSerializer和JsonArraySerializer,然后进行配置更改(例如Jackson中的DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)可能很有用。

#4


0  

Try this:

尝试这个:

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

#5


0  

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.

我的两分钱。