1. 概要
シナリオによっては、データベースクエリの結果をAPI呼び出しを介して別のシステムまたはメッセージングプラットフォームに送信する必要がある場合があります。 このような場合、データ交換形式としてJSONを使用することがよくあります。
このチュートリアルでは、 JDBC ResultSetオブジェクトをJSON形式に変換する複数の方法を紹介します。
2. コード例
コード例では、H2データベースを使用します。 JDBCを使用してテーブルwordsに読み込んだサンプルCSVファイルがあります。 サンプルCSVファイルの3行を次に示します。最初の行は、ヘッダーです。
Username,Id,First name,Last name
doe1,7173,John,Doe
smith3,3722,Dana,Smith
john22,5490,John,Wang
ResultSetを形成するコード行は次のようになります。
ResultSet resultSet = stmt.executeQuery("SELECT * FROM words");
JSON処理には、 JSON- Java ( org.json )ライブラリを使用します。 まず、対応する依存関係をPOMファイルに追加します。
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20220320</version>
</dependency>
3. 外部依存関係を使用しない
JDBC APIは、最新のJavaコレクションフレームワークよりも前のものです。 したがって、 for-each反復やStreamメソッドのようなものを使用することはできません。
代わりに、イテレータに依存する必要があります。 さらに、ResultSetのメタデータから列名の数とリストを抽出する必要があります。
これにより、行ごとにJSONオブジェクトを形成し、オブジェクトを List に追加し、最後にそのListをJSON配列に変換するという基本的なループが発生します。 これらの機能はすべて、org.jsonパッケージで利用できます。
ResultSetMetaData md = resultSet.getMetaData();
int numCols = md.getColumnCount();
List<String> colNames = IntStream.range(0, numCols)
.mapToObj(i -> {
try {
return md.getColumnName(i + 1);
} catch (SQLException e) {
e.printStackTrace();
return "?";
}
})
.collect(Collectors.toList());
JSONArray result = new JSONArray();
while (resultSet.next()) {
JSONObject row = new JSONObject();
colNames.forEach(cn -> {
try {
row.put(cn, resultSet.getObject(cn));
} catch (JSONException | SQLException e) {
e.printStackTrace();
}
});
result.add(row);
}
ここでは、最初にループを実行して各列の名前を抽出します。 後で、これらの列名を使用して、結果のJSONオブジェクトを形成します。
2番目のループでは、実際の結果を調べ、前の手順で計算した列名を使用して、それぞれをJSONオブジェクトに変換します。 次に、これらすべてのオブジェクトをJSON配列に追加します。
列名と列数の抽出はループから外しました。 これは、実行を高速化するのに役立ちます。
結果のJSONは次のようになります。
[
{
"Username":"doe1",
"First name":"John",
"Id":"7173",
"Last name":"Doe"
},
{
"Username":"smith3",
"First name":"Dana",
"Id":"3722",
"Last name":"Smith"
},
{
"Username":"john22",
"First name":"John",
"Id":"5490",
"Last name":"Wang"
}
]
4. デフォルト設定でのjOOQの使用
jOOQ フレームワーク(Javaオブジェクト指向クエリ)は、特に、JDBCおよびResultSetオブジェクトを操作するための便利なユーティリティ関数のセットを提供します。 まず、jOOQ依存関係をPOMファイルに追加する必要があります。
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.11.11</version>
</dependency>
依存関係を追加した後、ResultSetをJSONオブジェクトに変換するための単一行ソリューションを実際に使用できます。
JSONObject result = new JSONObject(DSL.using(dbConnection)
.fetch(resultSet)
.formatJSON());
結果のJSON要素は、fieldsとrecordsという2つのフィールドで構成されるオブジェクトです。ここで、fieldsには列の名前とタイプがあり、recordsには実際のデータが含まれています。 これは前のJSONオブジェクトとは少し異なり、サンプルテーブルでは次のようになります。
{
"records":[
[
"doe1",
"7173",
"John",
"Doe"
],
[
"smith3",
"3722",
"Dana",
"Smith"
],
[
"john22",
"5490",
"John",
"Wang"
]
],
"fields":[
{
"schema":"PUBLIC",
"name":"Username",
"type":"VARCHAR",
"table":"WORDS"
},
{
"schema":"PUBLIC",
"name":"Id",
"type":"VARCHAR",
"table":"WORDS"
},
{
"schema":"PUBLIC",
"name":"First name",
"type":"VARCHAR",
"table":"WORDS"
},
{
"schema":"PUBLIC",
"name":"Last name",
"type":"VARCHAR",
"table":"WORDS"
}
]
}
5. カスタマイズされた設定でのjOOQの使用
jOOQによって生成されたJSONオブジェクトのデフォルトの構造が気に入らない場合は、カスタマイズする余地があります。
これを行うには、RecordMapperインターフェイスを実装します。 このインターフェイスには、 Record を入力として受け取り、任意のタイプの目的のオブジェクトを返す map()メソッドがあります。
次に、jOOQ結果クラスの map()メソッドへの入力としてRecordMapperをフィードします。
List json = DSL.using(dbConnection)
.fetch(resultSet)
.map(new RecordMapper() {
@Override
public JSONObject map(Record r) {
JSONObject obj = new JSONObject();
colNames.forEach(cn -> obj.put(cn, r.get(cn)));
return obj;
}
});
return new JSONArray(json);
ここでは、 map()メソッドからJSONObjectを返しました。
結果のJSONは、セクション3と同様に次のようになります。
[
{
"Username":"doe1",
"First name":"John",
"Id":"7173",
"Last name":"Doe"
},
{
"Username":"smith3",
"First name":"Dana",
"Id":"3722",
"Last name":"Smith"
},
{
"Username":"john22",
"First name":"John",
"Id":"5490",
"Last name":"Wang"
}
]
6. 結論
この記事では、JDBC ResultSetをJSONオブジェクトに変換する3つの異なる方法について説明しました。
それぞれのアプローチには独自の用途があります。 何を選択するかは、出力JSONオブジェクトの必要な構造や、依存関係のサイズに考えられる制限などによって異なります。
いつものように、例のソースコードはGitHubで入手できます。