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

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

我目前正在开发一个 vertx.io 应用程序,并希望使用 provide 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) 格式之间进行转换,但这是一个非常粗暴和低效的工作流程。我也可能想出某种抽象包装器 extends/implements vertx json 库,但将所有功能传递给 gson,但这似乎也需要很多工作。

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

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

因此,我们通过 EventBus 作为 JsonObjects

发送了很多 pojo

我发现最简单的方法是使用 vert.x Json class,它有大量辅助方法可以转换为 Json Strings

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

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

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

public JsonObjectSerializable {
    public JsonObject toJson();
}

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

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

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

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

希望这对您有所帮助,

我相信 Jackson 的 ObjectMapper.convertValue(..) 函数不会通过 String 进行转换,而且 Vert.x 无论如何都在使用 Jackson 来管理 JsonObject。

JsonObject 仅具有表示值的底层映射,可通过 JsonObject.getMap() 访问,而 public ObjectMapper 实例上的 Jackson serializer/deserializer io.vertx.core.json.Json.

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

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

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

要从 Pojo 转换为 JsonObject,请使用 Jackson 转换为地图,然后在 JsonObject 上使用构造函数:

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

  • 如果您在定义中暗示了嵌套的 JsonObjects 或 JsonArray 对象,它们将默认实例化为地图和列表。当您访问指定这些类型的字段(例如使用 getJsonArray(..).

  • 时,JsonObject 将在内部重新包装它们
  • 因为 JsonObject 是自由格式的并且您正在转换为静态类型,所以您可能会遇到一些不需要的 UnrecognizedPropertyException 需要处理。创建自己的 ObjectMapper,添加顶点 JsonObjectSerializer 和 JsonArraySerializer,然后进行配置更改以适应(例如 Jackson 中的 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)可能很有用。

试试这个:

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

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

我认为按照您的描述使用 Gson 是目前最好的解决方案。

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

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

我的两分钱。

你可以试试:

new JsonObject().mapFrom(object)