EzJDBCの自動バインディングの秘密


EzJDBCで如何にして、テーブルのデータをエンティティにマッピングしているのか、技術的な面について説明したいと思います。


EzJDBCはテーブルの照会結果をEntityにマッピングするコードは下記のようになります。
例:CUSTOMERテーブルから名前(NANE)が"Taka"で始まるデータを照会し、結果をCustomerエンティティにマッピングするコード

CUSTOMER CS = new CUSTOMER();
List list = EzJDBC.froms(CS).where(CS.name.like("Taka%")).find(Customer.class);

照会したレコードの値は、エンティティのプロパティーに自動でバインドされることになります。
自動バインドは以下のルールによって行われます。

1.テーブルのカラム名と同名プロパティにバインドします。
2.プロパティ名はカラム名のキャメル記法にします。

ではEzJDBCは、いったいどの様にして自動バインドさせているのでしょうか?
世にO/Rマッパーは多種多様ありますが、自動バインドさせる方法は大体以下の3種類に分けられます。

1.ResultSetMetadataとリフレクションを使用して実行時に随時バインドするパターン
2.バインドするソースコードを事前に作成し実行時に利用するパターン
3.バイトコードエンハンスでバインドするソースコードを実行時に作成するパターン

それぞれメリデメはありますが、現在の主流は2か3だと思います(メリデメは主観です)

1.は一昔前の方法と言ってよいのではないかと思います。理由はリフレクションは動作が基本的に遅いためです(キャッシュしても遅い)。


2.は開発時にバインドするコード(例:customer.setName(resultSet.getString("NAME"))...)をscafoldやフレームワークで自動生成し、javaソース(class)としてプロジェクト内に配備します。
メリットは単純作業であるバインドするコードを開発者が書く必要がない。ソースがあるためデバックし易い。そして純粋なjavaコードなので早い。
デメリットはプロジェクトに自動生成クラスの数が激増する。SQL変更時に再作成が必要になる。ソースがあるため手が加えられる可能性がある。


3.はSQL発行時にバインドするコード(例:customer.setName(resultSet.getString("NAME"))...)をバイトコードエンハンスメントで作成する。
メリットは単純作業であるバインドするコードを開発者が書く必要がない。バインド用クラスがプロジェクト内に存在しない。そして純粋なjavaコードなので早い。
デメリットは実行時にバインドするコードを生成するため1回目の起動が遅い。

EzJDBCは3のバイトコードエンハンスメントで動的にレコードの値をエンティティにバインドするソースコードを作成しています。
例えば、上記のEzJDBCのコードを実行すると下記のバインド用ソースコードが作成されます(細部は省いてます)。

public static List getCustomerList(ResultSet resultSet) {
  List list = new ArrayList();
  while(resultSet.next()) {
    // Customerエンティティーを生成します
    Customer customer = new Customer();
    // 照会結果をCustomerにバインドします。
    customer.id = resultSet.getString(0);
    customer.name = resultSet.getString(1);
    customer.age = resultSet.getInt(2);
    ...
    // Customerエンティティを結果Listに追加します
    list.add(customer);
  }
  return list;
}

このソースはSQL実行時の1回目に作成されクラスローダーより読み込まれます(つまり普通のクラスと同じ扱いになる)、2回目以降は、EzJDBCは上記メソッドを呼び出し結果を取得します。


バイトコードエンハンスメントは超強力な機能です(但し多用すると黒魔術的になり根深いバグを生む可能性もあるので注意)、この機能があるため、EzJDBCは簡単に照会機能を記述する事ができ、高速に照会結果を取得する事ができるのです。


*今回の例では、EzJDBCのSQL自動生成機能を例にあげましたが、EzJDBCのSQLファイル・フリーも同様の動きをします。