Dozerとは
Dozer は Java Bean 間のマッパーライブラリです。あるオブジェクトから他のオブジェクトに、再帰的に値のコピーを行います。Dozer は、単純なプロパティマッピングから、複雑なタイプマッピング、単方向・双方向マッピング、暗黙的・明示的マッピングをサポートします。
2009年8月に5.1 がリリースされました。ライセンスはApache License Version 2.0となります。本家は以下となります。
http://dozer.sourceforge.net/
導入
以下のページよりDozerのアーカイブをダウンロードします。
http://sourceforge.net/projects/dozer/files/
ダウンロードしたファイルのJARファイル dist/dozer.jar をクラスパスに追加します。
その他に以下のcommons系のライブラリに依存しています。適宜ダウンロードしてクラスパスに追加します。
- commons-lang(今回は2.4)
- commons-logging(今回は1.1.1)
- commons-collections(今回は3.2.1)
- commons-beanutils(今回は1.8.0)
簡単なマッピング
最初の例では、ソースとなるデータオブジェクトの属性を、対象のオブジェクトの属性にコピーします。コピーする手順は以下のようにMapperのインスタンスのmapメソッドを呼び出すだけです。
Mapper mapper = new DozerBeanMapper(); DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class);
または、以下の様な使いかたもできます。
Mapper mapper = new DozerBeanMapper(); DestinationObject destObject = new DestinationObject(); mapper.map(sourceObject, destObject);
実際のソースは以下のようになります。
package etc9; import org.apache.commons.lang.builder.ToStringBuilder; import org.dozer.DozerBeanMapper; import org.dozer.Mapper; public class DozerSample1 { public static void main(String[] args) { SourceObject sourceObject = new SourceObject(); sourceObject.setName("hoge"); sourceObject.setDate(new java.util.Date()); Mapper mapper = new DozerBeanMapper(); DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class); System.out.println(ToStringBuilder.reflectionToString(destObject)); } public static class SourceObject { private String name; private java.util.Date date; public String getName() { return name; } public void setName(String name) { this.name = name; } public java.util.Date getDate() { return date; } public void setDate(java.util.Date date) { this.date = date; } } public static class DestinationObject { private String name; private String date; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } } }
出力結果は以下のようになり、DestinationObjectに値がコピーされていることが分かります。
etc9.DozerSample1$DestinationObject@b988a6[name=hoge,date=Tue Sep 22 23:14:41 JST 2009]
Dozerマッピングを実行した後、destination オブジェクトの新しいインスタンスが作成され、source オブジェクトの同名フィールドの値がコピーされます。異なる型のフィールドが存在する場合、Dozerマッピングエンジンは自動的に型変換を行います。
現実的には、Mapper のインスタンスを毎回作成するのは望ましくありません。一般的には、1つのVMに対して、1つの Mapper インスタンスのみを持つべきです。SpringのようなIoCフレームワークを利用している場合には、singleton="true" と定義します。そうでない場合には、DozerBeanMapperSingletonWrappe クラスが提供されているので、これを使うことになるでしょう。
XMLによるカスタムマッピングの指定
異なる2つのオブジェクトのフィールド名や型が異なる場合、カスタムマッピングをXMLにて指定します。Dozerエンジンは、このカスタムマッピングXMLファイルを実行時に使用し、オブジェクトのマッピングを行います。マッピングを作成することで、Dozerエンジンは、定義したオブジェクト間のマッピングを双方向に解決します。(この時、フィールド名が同じものについては、マッピング定義を行う必要はありません)
マッピングの定義は以下のように、AとBのクラスを指定し、対応フィールドを列挙するだけです。
<mapping> <class-a>yourpackage.yourSourceClassName</class-a> <class-b>yourpackage.yourDestinationClassName</class-b> <field> <a>yourSourceFieldName</a> <b>yourDestinationFieldName</b> </field> </mapping>
では実際に試してみましょう。対象となるソースは以下です。ここでは、DozerBeanMapperSingletonWrapper を利用します。
package etc9; import org.apache.commons.lang.builder.ToStringBuilder; import org.dozer.DozerBeanMapperSingletonWrapper; import org.dozer.Mapper; public class DozerSample1 { public static void main(String[] args) { SourceObject sourceObject = new SourceObject(); sourceObject.setDate(new java.util.Date()); Mapper mapper = DozerBeanMapperSingletonWrapper.getInstance(); DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class); System.out.println(ToStringBuilder.reflectionToString(destObject)); } public static class SourceObject { private java.util.Date date; public java.util.Date getDate() { return date; } public void setDate(java.util.Date date) { this.date = date; } } public static class DestinationObject { private String destDate; public String getDestDate() { return destDate; } public void setDestDate(String destDate) { this.destDate = destDate; } } }
DozerBeanMapperSingletonWrapper を利用した場合、クラスパスのルートとなるディレクトリに(つまりEclipseで言うと、ソースフォルダの直下)に dozerBeanMapping.xml という名前でマッピングXMLを用意します。XMLファイルは以下のようになります。
<?xml version="1.0" encoding="UTF-8"?> <mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd"> <mapping> <class-a>etc9.DozerSample1$SourceObject</class-a> <class-b>etc9.DozerSample1$DestinationObject</class-b> <field> <a>date</a> <b>destDate</b> </field> </mapping> </mappings>
ここではインナークラスを使用しているため、「etc9.DozerSample1$SourceObject」のような指定としていますが、通常は「.」でクラス名を指定することになるでしょう。
実行結果は以下のようになります。
etc9.DozerSample1$DestinationObject@10da5eb[destDate=Wed Sep 23 00:10:06 JST 2009]
String と Date のマッピング
StringとDateのマッピングには、Dateフォーマットの指定ができます。先の例で言うと、以下のように指定することができます。
<?xml version="1.0" encoding="UTF-8"?> <mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd"> <configuration> <stop-on-errors>true</stop-on-errors> <date-format>yyyy/MM/dd HH:mm</date-format> <wildcard>true</wildcard> </configuration> <mapping> <class-a>etc9.DozerSample1$SourceObject</class-a> <class-b>etc9.DozerSample1$DestinationObject</class-b> <field> <a>date</a> <b>destDate</b> </field> </mapping> </mappings>
これにより、出力結果は以下の様になります。
etc9.DozerSample1$DestinationObject@1b3f829[destDate=2009/09/23 00:17]
マッピングファイルの指定
先の例では、DozerBeanMapperSingletonWrapper にてデフォルトのマッピングファイルを読み込んでいましたが、以下のようにマッピングファイルを指定することもできます。
List<String> myMappingFiles = new ArrayList<String>(); myMappingFiles.add("dozerBeanMapping.xml"); DozerBeanMapper mapper = new DozerBeanMapper(); mapper.setMappingFiles(myMappingFiles); DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class);
なお、クラスパス外のマッピングファイルを読み込むには「"file:c:\somedozermapping.xml" 」のように指定します。
Springとの統合
Spring設定ファイルに以下のようなDozerBeanMapperのbean定義を追加します。プロパティとして、mappingFilesを追加できます。
<bean id="mapper" class="org.dozer.DozerBeanMapper"> <property name="mappingFiles"> <list> <value>dozer-global-configuration.xml</value> <value>dozer-bean-mappings.xml</value> </list> </property> </bean>
Dozer には Spring FactoryBean インターフェースを実装したDozerBeanMapperFactoryBeanが提供されており、以下の様な定義も可能。
<bean class="org.dozer.spring.DozerBeanMapperFactoryBean"> <property name="mappingFiles"> <list> <value>dozer-global-configuration.xml</value> <value>dozer-bean-mappings.xml</value> </list> </property> </bean>