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

时间:2015-08-17 04:44:56

标签: java json vert.x

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

this.backingObject.get(KEY_FOR_THIS_PROPERTY);

现在这一切都很好,但它不会特别好地扩展。它看起来也很脏,特别是在使用嵌套数组或对象时。例如,如果我希望只有在知道实际数据时才能填充字段,我必须检查数组是否存在,以及它是否创建它并将其存储在对象中。然后我可以在列表中添加一个元素。例如:

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

我已经考虑过潜在的解决方案,但并不特别喜欢它们中的任何一种。也就是说,我可以使用带有注释支持的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 json库,但是将所有的功能都传递给了gson,但这似乎也是很多工作。

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

6 个答案:

答案 0 :(得分:25)

我刚刚向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)

在内部使用ObjectMapper#convertValue(...),请参阅Tim Putnam的回答,了解这种方法的注意事项。代码为here

答案 1 :(得分:7)

不确定我是否理解正确,但听起来您正试图找到一种将POJO转换为JsonObject的简单方法?

所以,我们通过EventBus发送的许多pojos为JsonObject s

我发现最简单的方法是使用vert.x Json类,其中包含大量辅助方法,可以转换为Json Strings

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

有时您需要添加一些自定义(de)序列化程序,但我们始终坚持Jackson - 这就是Vert.x正在使用的内容,因此它们开箱即用。

我们实际做的是提供如下界面:

public JsonObjectSerializable {
    public JsonObject toJson();
}

我们需要通过EventBus发送的所有pojos都必须实现此接口。

然后我们的EventBus发送代码看起来像(简化):

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

此外,由于我们通常不对Pojos进行单元测试,因此添加此interface会鼓励开发人员对其转换进行单元测试。

希望这有帮助,

威尔

答案 2 :(得分:7)

我相信Jackson的ObjectMapper.convertValue(..)函数不会通过String进行转换,Vert.x也会使用Jackson来管理JsonObject。

JsonObject只有一个底层地图,表示可通过JsonObject.getMap()访问的值,以及io.vertx.core.json.Json中公共ObjectMapper实例上的Jackson序列化器/反序列化器

要在JsonObject和用Jackson序列化的Pojos中表达的数据模型之间切换,您可以这样做:

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

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

要从Pojo转换为JsonObject,请转换为杰克逊的地图,然后使用JsonObject上的构造函数:

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

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

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

答案 3 :(得分:0)

试试这个:

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

答案 4 :(得分:0)

我认为如你所描述的那样使用Gson是目前最好的解决方案。

虽然我同意如果Vert.x中包含一个协议层,它确实是一等奖,使用Gson可以使您的服务器内部非常有条理并且不太可能成为性能瓶颈。

当且仅当此策略成为性能瓶颈时,您才能达到设计更好解决方案的程度。之前的任何事情都是过早的优化。

我的两分钱。

答案 5 :(得分:-1)

您可以尝试:

new JsonObject().mapFrom(object)