iBATISのGenerics対応を考える

ActiveObjectsのGenericsの使い方はとても参考になるなあ。Genericsって使うことはあったけどAPI作成側になって考えると奥深い。
愛用しているiBATISもGenricsが使えたらいいのに」と思って考案してみました。

SqlMapClientGenというクラスを作って、処理の大部分を内包しているSqlMapClientへ委譲する。Generics対応したいところだけ書き換えた。@deprecatedになっているメソッドは廃止した。あとGenerics対応したRowHandler、RowHandlerGenを作成した。
select系だけしか関係ないので、updateやinsertは変更していない。

実装コードはこちら。

シンプルなコード例(simple examples)


//生成
SqlMapClientGen client = new SqlMapClientGen(originalSqlMapClient);

newしてるけど、DIコンテナなんかで生成するようにしたほうがかっちょこいいでしょう。


//queryForList

List<empEntity> empList = client.<empEntity>queryForList("select");
List<empEntity> empList = client.queryForList("select");

//拡張for文 (enhanced for statement)
for (EmpEntity emp : empList){
  System.out.println(emp);
}

//queryForObject

EmpEntity emp = client.<empEntity>queryForObject("selectByPK", 7698);
EmpEntity emp = client.queryForObject("selectByPK", 7698);

メソッド名の前にパラメータクラスを指定。
2008/06/04追記:戻り値で型の特定が出来るので、メソッド名の前に型パラメータを指定するのは、必ずしも必要ではなかったです。


//queryWithRowHandler
client.queryWithRowHandler("select", new RowHandlerGen<empEntity>(){
  @Override
  public void handleRow(EmpEntity row) {
    System.out.println("[" + row.getEmpno() + "]" + row.getEname());
  }
});

RowHandlerはクラス名のあとにパラメータクラス名を指定。

Generics対応といっても本格的なことはしておらず、SqlMapClientGen側で@SuppressWarningsしているだけです。なのでSqlMap.xmlで定義したresultClassと型があっていなくても、コンパイルは出来てしまいます。(タイプセーフとはいえない)
「パラメータクラス<t>を書くのと、キャスト(T)するのは手間は同じじゃないか!」と言われそうですが、キャストよりもすっきりしませんか?(しないか)でもRowHandlerあたりはちょっといい感じじゃないかしら?それに利用コード側には@SuppressWarningsがつかないから良いかと。
でも、SqlMap.xmlとGenericsで同じクラス名書いているのはDRY原則に反するので、SqlMap.xmlのresultClass名は記述不要にするとか。そうしたら大改造だな。

2008/06/04追記:戻り値でListを受け取る場合などは、型パラメータを指定する必要はなかったです。
例えば、次のような拡張forの場合は型パラメータを指定しなければなりません。
for (EmpEntity emp : client.<empEntity>queryForList("select"))
一度Listで受け取る場合には不要でした。


List<empEntity> empList = client.queryForList("select");
for (EmpEntity emp : empList)

いっそう便利に使えるかと思います。

iBATIS in Action
iBATIS in Action


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)