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 に追加し、最後にそのListJSON配列に変換するという基本的なループが発生します。 これらの機能はすべて、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で入手できます。