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
List
//拡張for文 (enhanced for statement)
for (EmpEntity emp : empList){
System.out.println(emp);
}
//queryForObject
EmpEntity emp = client.
EmpEntity emp = client.queryForObject("selectByPK", 7698);
メソッド名の前にパラメータクラスを指定。
2008/06/04追記:戻り値で型の特定が出来るので、メソッド名の前に型パラメータを指定するのは、必ずしも必要ではなかったです。
//queryWithRowHandler
client.queryWithRowHandler("select", new RowHandlerGen
@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.
一度Listで受け取る場合には不要でした。
List
for (EmpEntity emp : empList)
いっそう便利に使えるかと思います。