Dozerライブラリを利用し、JavaBeanのマッピングを実現する。


Webアプリケーションにおいて、異なるレイヤ間で、データの受け渡しをする場合など、Beanマッピングが必要となるケースは多いです。その時に、[Dozer](http://dozer.sourceforge.net/)を使用することで下図のように、変換元のBeanから変換先のBeanに、再帰的に値をコピーし、コピー元JavaBeanとコピー先JavaBeanで異なるフィールド名、異なるデータ型のコピーも容易に行うことができます。
![2016-06-30_152457.png](https://qiita-image-store.s3.amazonaws.com/0/123138/bfbe6ecb-0181-c089-be78-c9ba959b39a1.png)

Dozerライブラリのダウンロード(https://sourceforge.net/projects/dozer/files/dozer/5.3.2/)


#使い方

１．コピー元とコピー先JavaBeanの例

```java
// コピー元JavaBean
public class SourceBean implements Serializable {

    private String productId;
	
    private int productPrice;
	
    private String productionDate;
	
    private byte[] productImage;
	
    private List<String> shopList;

    // getter、setter省略
}
```

```java
// コピー先JavaBean
public class DestinationBean {

    private String productId;
	
    private int price;

    private Timestamp date;

    private String productImage;

    private String[] shopList;

    // getter、setter省略
}
```

２．DozerのBean定義を作成する。

```xml
<!-- Dozerの設定 -->
<bean name="dozer" class="org.dozer.spring.DozerBeanMapperFactoryBean">
    <property name="mappingFiles" value="classpath*:/META-INF/dozer/*-mapping.xml" />
</bean>
```

３．Dozerユーティルを使用し、Beanマッピングを行う。

```java
@Resource
private DozerBeanMapper dozer;
    
public void execute(SourceBean sb) {
	
	// JavaBeanのマッピング
	DestinationBean dBean = dozer.map(sb, DestinationBean.class);
}
```

##データ型は同じ、フィールド名が異なる場合のマッピング

フィールド名が異なる場合、マッピング定義XMLファイルを作成し、Beanマッピングするフィールドを定義することで変換できます。

・コピー元フィールド`productPrice`
・コピー先フィールド`price`;

META-INF/dozerフォルダ内に、マッピング定義XMLファイル「dozer-mapping.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>bean.SourceBean</class-a> <!-- コピー元JavaBean -->
      <class-b>bean.DestinationBean</class-b> <!-- コピー先JavaBean -->
      <field>
        <a>productPrice</a> <!-- コピー元フィールド -->
        <b>price</b> <!-- コピー先フィールド -->
      </field>
    </mapping>

</mappings>
```


##フィールド名は同じ、データ型が異なる場合のマッピング

フィールドの型が異なる場合、型変換がサポートされている型は、自動でマッピングできます。
例 : Date-> Timestamp
※自動変換のサポートについては、[Dozerマニュアル](http://dozer.sourceforge.net/dozer-user-guide.pdf)をご参照ください。


型変換がサポートされていない型は、カスタムコンバーターを作成し、Beanマッピングを行います。
・コピー元データ型：byte[]
・コピー先データ型：String（Base64エンコード）

・コピー元データ型：String
・コピー先データ型：Timestamp

１．META-INF/dozerフォルダ内に、dozer-configration-mapping.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">

    <configuration>
        <custom-converters>
            <!--byte[]から文字列への変換-->
            <converter type="util.ByteToStringConverter"> <!--コンバータークラス-->
                <class-a>[B</class-a> <!--変換元データ型：byte[]-->
                <class-b>java.lang.String</class-b> <!--変換先データ型：String-->
            </converter>
            
            <!--文字列からTimestampへの変換-->
            <converter type="util.StringToTimestampConverter"> <!--コンバータークラス-->
                <class-a>java.lang.String</class-a> <!--変換元データ型：String-->
                <class-b>java.sql.Timestamp</class-b> <!--変換元データ型：Timestamp-->
            </converter>
            
        </custom-converters>
    </configuration>

</mappings>
```

２．カスタムコンバータークラスは以下のように作成する。

・byte[]配列とBase64文字列の相互変換クラス

```java
public class ByteToStringConverter extends DozerConverter<byte[], String> {

    /**
     * コンストラクタ
     */
	public ByteToStringConverter() {
		super(byte[].class, String.class);
		
	}

	/**
	 * 文字列からbyte配列への変換処理
	 * <p>
	 * 指定された文字列に対して、Base64デコード処理を行い、
	 * Byte配列に変換し、返却する。
	 * </p>
	 * @see org.dozer.DozerConverter#convertFrom(java.lang.Object, java.lang.Object)
	 */
	@Override
	public byte[] convertFrom(String arg0, byte[] arg1) {
		return java.util.Base64.getDecoder().decode(arg0);
	}

	/**
     * byte配列から文字列への変換処理
     * <p>
     * 指定されたbyte配列に対して、Base64エンコード処理を行い、
     * 文字列に変換し、返却する。
     * </p>
	 * @see org.dozer.DozerConverter#convertTo(java.lang.Object, java.lang.Object)
	 */
	@Override
	public String convertTo(byte[] arg0, String arg1) {
		return java.util.Base64.getEncoder().encodeToString(arg0);
	}
}
```

・文字列とTimestampの相互変換クラス

```java

public class StringToTimestampConverter extends DozerConverter<String, Timestamp> {

    /**
     * コンストラクタ
     */
	public StringToTimestampConverter() {
		super(String.class, Timestamp.class);
		
	}

	/**
	 * Timestampから文字列への変換処理
	 * 
	 * @see org.dozer.DozerConverter#convertFrom(java.lang.Object, java.lang.Object)
	 */
	@Override
	public String convertFrom(Timestamp arg0, String arg1) {
		
		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(arg0);
	}
	
	/**
     * 文字列からTimestampへの変換処理
     * 
	 * @see org.dozer.DozerConverter#convertTo(java.lang.Object, java.lang.Object)
	 */
	@Override
	public Timestamp convertTo(String arg0, Timestamp arg1) {

		try {
			
			return new Timestamp(new SimpleDateFormat("yyyy-MM-dd").parse(arg0).getTime());
			
		} catch (ParseException e) {
			throw new RuntimeException(e);
		}
	}
}

```