web-dev-qa-db-ja.com

POJOからvertx.ioのJsonObjectへのエレガントなマッピング?

現在、 vertx.io アプリケーションで作業しており、データストレージに提供mongo apiを使用したいと考えています。私は現在、すべてのgetおよびsetメソッドが次のようなものに置き換えられている標準のJsonObjectクラスの上にかなり不格好な抽象化を持っています。

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

私は潜在的な解決策について考えましたが、特にそれらのどれも好きではありません。つまり、Icouldは、コード内のデータを操作する目的でオブジェクトの読み込みを処理するために、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を使用して、より友好的で保守可能なシリアル化を実現する良い方法はありますか?

18
grdaneault

JsonObjectとJavaオブジェクトインスタンス間で変換するための2つの新しい便利な関数を定義するVert.xにパッチを提出しました。 。

_// 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 です。

27
Luke Hutchison

私があなたを正しく理解しているかどうかはわかりませんが、POJOをJsonObjectに変換する簡単な方法を見つけようとしているように聞こえますか?

したがって、EventBusJsonObjectsとして送信する多くのpojoがあります。

最も簡単な方法は、vert.xJsonは、JsonStringsとの間で変換するヘルパーメソッドのロードを持ちます。

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

また、一般的にPojoの単体テストは行わないため、このinterfaceを追加すると、開発者はコンバージョンの単体テストを行うことができます。

お役に立てれば、

意志

7
Will

ジャクソンのObjectMapper.convertValue(..)関数は文字列を介して変換せず、Vert.xはとにかくJsonObjectの管理にJacksonを使用していると思います。

JsonObjectには、値を表す基になるマップがあり、JsonObject.getMap()を介してアクセスでき、io.vertx.core.jsonのパブリックObjectMapperインスタンスにJacksonシリアライザー/デシリアライザーがあります。ジョンソン。

JsonObjectとJacksonでシリアル化可能なPojosで表現されたデータモデルを切り替えるには、次のようにします。

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

私はこれが文字列を経由するよりも効率的であると推測しますが(単なる推測です)、環境に合わせてデータクラスを変更するという考えは嫌いですので、コンテキスト-フォーム対パフォーマンスに依存します。

PojoからJsonObjectに変換するには、Jacksonでマップに変換し、JsonObjectでコンストラクターを使用します。

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

  • 定義でネストされたJsonObjectsまたはJsonArrayオブジェクトを暗示している場合、それらはデフォルトでMapsおよびListsとしてインスタンス化されます。 JsonObjectは、これらのタイプを指定するフィールドにアクセスすると(たとえば、getJsonArray(..)で)内部的にこれらを再ラップします。

  • JsonObjectは自由形式であり、静的な型に変換しているため、処理するために不要なUnrecognizedPropertyExceptionが発生する場合があります。独自のObjectMapperを作成し、vertx JsonObjectSerializerとJsonArraySerializerを追加し、それに合わせて構成を変更すると便利です(ジャクソンのDeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIESなど)。

7
Tim Putnam

あなたが説明したようにGsonを使用することは、現時点で最良の解決策だと思います。

プロトコル層がVert.xに含まれていた場合、それが実際に最優秀賞となることに同意しますが、Gsonを使用すると、サーバー内部がかなり整理され、パフォーマンスのボトルネックになることはほとんどありません。

この戦略がパフォーマンスのボトルネックになったときのみ、より良いソリューションを設計するポイントに達しました。それより前のすべてが時期尚早の最適化です。

私の2セント。

0
Daniel Gerson

これを試して:

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