TypeHandlerを使用した型の変換
iBATISは、データベースのデータ型とJavaのデータ型を交換してくれます。例えばデータベースのCHAR型、VARCHAR型をJavaのString型のプロパティにセットできます。その逆も可能です。このように基本的なデータ型はiBATISの標準機能でマッピングできますが、iBATISがサポートしていないデータ型同士の変換はできません。
TypeHandlerを使用することで、任意のデータベースデータ型→任意のJavaオブジェクト、およびその逆が可能になります。
サンプルプログラムでは、データベースに格納された画像ファイルのイメージデータ(バイナリデータ)から、SwingのImageIcon
オブジェクトに交換する例を紹介します。
サンプルは社員に対応する社員画像を一覧表示します。実行結果はこのようなイメージです。
検索結果を受け取るEmpImageオブジェクト
public class EmpImage { private int empno; private String ename; private ImageIcon img; public ImageIcon getImg() { return img; } public void setImg(ImageIcon img) { this.img = img; } //以下同様なsetter,getter 省略 }
imgプロパティはjavax.swing.ImageIcon
型のプロパティです。データベースにはImageIcon
に相当する型はないので、通常の検索ではimg
プロパティに値をセットできません。
SqlMap
<!-- イメージ取得用 --> <resultMap id="empImageMap" class="examples.dto.EmpImage"> <result property="empno" column="EMPNO"/> <result property="ename" column="ENAME"/> <result property="img" column="IMG" typeHandler="examples.ImageIconTypeHandler"/> </resultMap> <select id="getImage" resultMap="empImageMap"> SELECT A.EMPNO, A.ENAME, B.IMG FROM EMP AS A INNER JOIN EMPIMAGE AS B ON A.EMPNO = B.EMPNO </select>
javax.swing.ImageIcon
が取得できるようにresultMap
を定義します。imgプロパティのtypeHandler属性に、これから自作するImageIconTypeHandler
を指定します。
TypeHandler
TypeHandlerはデータベースの検索結果からResultClassのオブジェクトに変換するためのクラスです。TypeHandlerを作成する際には、TypeHandlerCallback
インターフェースを実装するのが楽です。
public class ImageIconTypeHandler implements TypeHandlerCallback { /** * LONGVARBINARYのイメージデータをImageIconに変換する */ public Object getResult(ResultGetter getter) throws SQLException { byte[] imageBytes = getter.getBytes(); if (imageBytes == null){ return new ImageIcon(); } return new ImageIcon(getter.getBytes()); } /** * ImageIconをJPEGバイナリデータにし、LONGVARBINARYにセットする */ public void setParameter(ParameterSetter setter, Object parameter) throws SQLException { //検索のみなのでサンプルでは使われていません。 } public Object valueOf(String s) { return ""; //未実装 } }
ImageIconTypeHandler
は、データベースのLONGVARBINARY型のデータから、java.swing.ImageIcon
オブジェクトを生成するTypeHandlerです。
このクラスの主な役割は2つです。1つはデータベースから取得したバイナリデータをImageIcon
オブジェクトに変換します(DB→Java)。もう1つはJavaのImageIcon
オブジェクトを、JPEG形式のバイナリデータに変換し、LONGVARBINARY型の列にセットします(Java→DB)。
getResult
がデータベースからのデータをJavaオブジェクトに変換するメソッドです。ResultGetter
はJDBCのResultSet
に似た作りになっていて、ここからデータベースの生のデータを取得できます。取得したデータを自由に変換しJavaオブジェクトとして返却します。
setParameter
はJavaオブジェクトをデータベースにセットするためのメソッドです。ParameterSetter
はJDBCのPreparedStatement
に値を格納する時に似ています。今回のサンプルでは、DBの検索結果を表示するだけで更新処理はないので、setParameter
は使用されません。
valueOf
メソッドは文字列表現からJavaオブジェクトに変換するためのメソッドです。
実行プログラム
//EmpImageのリストを取得 List<EmpImage> list = (List<EmpImage>)sqlMap.queryForList("getImage"); //検索結果をJFrameで表示する。 //・・・省略・・・ for (EmpImage empimage : list){ //JLabelにImageIconと社員名をセット JLabel label = new JLabel(empimage.getEname(), empimage.getImg(), JLabel.LEFT); frame.getContentPane().add(label); //JLabelを貼り付け } //・・・省略・・・
Swingコンポーネントを使用して、検索結果の画像をラベルとして表示します。TypeHandlerを使用することで、あたかもデータベースにImageIconが格納されているように取得できます。
TypeHandlerの実装は自由なので、データベースの中に格納されたファイルパスの文字列からjava.io.File
オブジェクトを生成したり、データベースのURL文字列から、インターネット上のファイルをHTTP経由で取得し、そのリソースを保持するといったことが実装できます(当然このような事をした場合、検索パフォーマンスは低下するので用途は検討する必要があります)。
まとめ
今回の記事では次の2つについて紹介しました。
- RowHandlerで検索結果に対して1件ずつ任意の処理を行うことができます
- TypeHandlerでデータベース⇔Javaオブジェクト間の自由な型交換が可能になります
iBATISは標準のままでも便利な機能を持っていますが、機能を拡張したい場合にも柔軟に対応できます。