JavaレコードとJSONライブラリによるAutonomous JSON Database (2021/04/22)
JavaレコードとJSONライブラリによるAutonomous JSON Database (2021/04/22)
http://www.igfasouza.com/blog/autonomous-json-database-with-java-records-and-json-libs/
Autonomous JSON Database(AJD)の発表を見てから、Javaレコードを使用することが可能かどうか、またJSONのシリアライズとデシリアライズの部分はどのようになるのか気になっていました。
図1: AJDインスタンスを作成する基本的な手順を示した簡易アニメーション
先日、Oracle社がFree AJDを発表しましたが、私は自分のテストをブログに書くことにしました。AJDの詳細についてはこちらをご覧ください。
すべてはここから始まりました。
このドキュメントを見て、新しいドキュメントを作成するには、文字列を送信する必要があることを知りました。
// Create a JSON document.
OracleDocument doc = db.createDocumentFromString("{ "name" : "Alexander" }");
そこで、オブジェクトをJSONにシリアライズ、デシリアライズする最良の方法は何か、また、Javaレコードを使用することはできないかと考えました。
JDK 14では、新しい種類の型宣言であるレコードが導入されました。レコードは、列挙型のように、クラスを制限したものです。
レコードは、「プレーンデータキャリア」と呼ばれる、変更を前提としないデータや、コンストラクタやアクセッサなどの最も基本的なメソッドのみを含むクラスに最適です。
クラスとレコードの重要な違いは、レコードはインスタンスにデータを設定したり取得したりするのに必要な定型的なコードをすべて排除することを目的としている点です。
レコードは、コンストラクタ、フィールドゲッタ、hashCode()、equals()、toString()などのメソッドを生成するJavaコンパイラにこの責任を移します。
はい、レコードを使用することは可能ですが、ここで最も重要なことは、オブジェクトをJSONにシリアライズおよびデシリアライズする方法です。
そのためには、JSONライブラリのオプションを確認する必要があります。
図2:最も人気のあるJSONライブラリ
実際のところ、オブジェクトをJSONにフォーマットするライブラリはすでにたくさん存在します。
そこで、JSON-B、Jackson、Gsonという最も一般的なJSONライブラリを比較するテストを行うことにしました。
JSON-BはJakarta EEの仕様で、JSONをJavaオブジェクトに変換する(そして元に戻す)ためのAPIを提供しています。
FasterXML Jacksonは、JSON-B仕様の実装ではありませんが、JSONとJavaオブジェクト間の同様のマッピング機能を提供します。
JacksonとJSON-Bの実装では、詳細なマッピング動作が異なります。
Gsonは、JavaオブジェクトをJSON表現に変換するために使用できるJavaライブラリです。また、JSONの文字列を同等のJavaオブジェクトに変換するのにも使えます。
Gsonは任意のJavaオブジェクトを扱うことができ、ソースコードを持たない既存のオブジェクトも扱うことができます。
図3: Jakarta EEとMicroprofileの比較
MicroprofileのJSON仕様を検索してみましたが、特に何も見つからず、JSOB-Bの考え方を踏襲しているように見えました。(ここで何か知っていることがあれば、コメントをお願いします。)
JSON-Bがリリースされる前(Java EE 8の一部として登場)、JSON-PはJSONと対話するためのJava EEの標準化された方法でした。
JSON-Pは、JSONの処理と変換のための2つのモデル(ストリーミングとオブジェクト)を提供する下位レベルのAPIです。
Eclipse Yassonは、リファレンス実装
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>yasson</artifactId>
<version>1.0.6</version>
<scope>test</scope>
</dependency>
mavenの依存関係を追加しただけで、Locationのコンストラクタに@JsonbCreatorアノテーションを追加する必要がありました。
他の実装もあるようです。
- Wildfly (23.0.0.Final)
- Payara (5.2021.1)
- OpenLiberty (21.0.0.3)
- Quarkus (1.13.2.Final)
- Helidon (2.2.2)
Jacksonの場合
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.0</version>
</dependency>
以下を追記
final ObjectMapper mapper = new ObjectMapper()
.enable(SerializationFeature.INDENT_OUTPUT);
Gsonの場合
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>
to Stringメソッドをオーバーライド
@Override
public String toString() {
Gson gson = new Gson();
return gson.toJson(this);
}
私のGitHubでコードを確認、入手することができます。
このコードのポイントは、これらの行が同じ結果をもたらすということです。
OracleDocument doc = db.createDocumentFromString(la.toString());
OracleDocument doc = db.createDocumentFromString(laAPI.toString());
OracleDocument doc = db.createDocumentFromString(laJackson.toString());
OracleDocument doc = db.createDocumentFromString(jsonb.toString());
また、オブジェクトとJSONを比較して、それらが等しいかどうかを検証するテストも追加しました。
図4: Java Dukeのシリアル化とシリアル化解除
最近、QuarkusがOracle JDBCドライバ拡張機能をリリースしたのを見て、この拡張機能は何が特別なのか、この拡張機能はSODAをサポートしているのか、していないのかという質問が出始めました。
私はこの拡張機能の実装の詳細を知りませんし、テストする時間もありませんでしたが、QuarkusではJSON-BかJacksonのどちらかを選択することができ、私がテストで実証したように、それは機能し、同じ結果を生成します。(テストをしてみて、違いがあった場合はコメントで教えてください)
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
もし、自分が使っているのがどの実装なのかわからなくなってしまったら、どの実装が使われているのかを調べることができます。
次のクラスのパッケージ名を確認するだけで十分です。
JsonbBuilder.create().getClass()
まとめ
JSONのシリアライズとデシリアライズにはレコードを使うことができます。
どのようなJSON lib APIを使用しても、結果は同じです。
リンク
http://oracle.github.io/soda-for-java/
https://docs.oracle.com/cd/E56351_01/doc.30/e58124/soda_for_java.htm#ADSDA144
https://docs.oracle.com/en/java/javase/14/language/records.html
https://javaee.github.io/jsonb-spec/users-guide.html
https://javaee.github.io/jsonp/
https://blogs.oracle.com/datawarehousing/autonomous-database-newsletter-august-20-2020
コメント
コメントを投稿