MapStructでBeanマッピング その3

前回の続き

http://qiita.com/kentama/items/09a8573bd5d0831b470e
http://qiita.com/kentama/items/55c71ca28f0c5af8d4ed

# 型変換とフォーマット

int -> String のようにマッピング時に型変換を行うことができる。
その際に、フォーマットの指定を行うこともできる。

```java:Bean
public class Hoge {
    private String date;
    private String number;

   // constructor/getter/setter
}

public class Fuga {
    private LocalDate date;
    private int number;

   // constructor/getter/setter
}
```

## Mapperの作成

```java
@Mapper
public interface ConversionMapper {
    ConversionMapper INSTANCE = Mappers.getMapper(ConversionMapper.class);

    @Mapping(target = "date", source = "date", dateFormat = "yyyy年MM月dd日") // (1)
    @Mapping(target = "number", source = "number", numberFormat = "#,###") // (2)
    Hoge convert(Fuga fuga);
}
```

(1) `dateFormat` 属性に日付のフォーマットを指定する。
(2) `numberFormat` 属性に数値のフォーマットを指定する。

## 実行

```java
Fuga fuga = new Fuga(LocalDate.of(2017, 4, 1), 1234567890);
Hoge hoge = ConversionMapper.INSTANCE.convert(fuga);

System.out.println(hoge.getDate()); // 2017年04月01日
System.out.println(hoge.getNumber()); // 1,234,567,890
```

## リストの型変換

`@IterableMapping` を使用することで、リストの型変換もすることができる。
今回は、int -> Stringの変換を行い、3桁のゼロ埋めをする。

### Mapperの作成

```java
@Mapper
public interface ConversionMapper {
    ConversionMapper INSTANCE = Mappers.getMapper(ConversionMapper.class);

    @IterableMapping(numberFormat = "000")
    List<String> zeroPadding(List<Integer> numbers);
}
```

### 実行

```java
List<String> numbers = ConversionMapper.INSTANCE.zeroPadding(Arrays.asList(1, 2, 56, 76, 863));
System.out.println(numbers); // [001, 002, 056, 076, 863]
```

---

# Mapperの再利用

Mapperから他のMapperを利用することができる。
MapStructが生成したMapper、または独自に実装したMapperを指定できる。

```java:Bean
public class Hoge {
    private String date;

    // constructor/getter/setter
}

public class Fuga {
    private LocalDate date;

    // constructor/getter/setter
}
```

## Mapperの作成

今回は LocalDate -> String変換 の独自Mapperを作成し、それを再利用させる。

```java:独自Mapper
public class LocalDateMapper {
    public String asString(LocalDate date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        return date != null ? date.format(formatter) : null;
    }
}
```

```java
@Mapper(uses = LocalDateMapper.class) // (1)
public interface InvokingOtherMapper {
    InvokingOtherMapper INSTANCE = Mappers.getMapper(InvokingOtherMapper.class);

    Hoge fugaToHoge(Fuga fuga);
}
```

(1) `uses` 属性に再利用するMapperを指定する。

## 実行

```java
Fuga fuga = new Fuga(LocalDate.of(2017, 4, 1));
Hoge hoge = InvokingOtherMapper.INSTANCE.fugaToHoge(fuga);

System.out.println(hoge.getDate()); // 2017年04月01日
```

---

# 限定子（Qualifier）の利用

独自に作成したマッピングロジックにアノテーションを付与し、Mapperで独自のマッピングロジックを利用するようにすることができる。
ここでは例として大文字と小文字に変換するマッピングを行う。

```java:Bean
public class Hoge {
    private String hoge1;
    private String hoge2;

    // constructor/getter/setter
}

public class Fuga {
    public String fuga1;
    public String fuga2;

    // constructor/getter/setter
}
```

## マッピングロジックの作成

```java
public class Characters {

    public String upperCase(String string) {
        return (string == null) ? null : string.toUpperCase();
    }

    public String lowerCase(String string) {
        return (string == null) ? null : string.toLowerCase();
    }
}
```

## アノテーションの作成

```java
@Qualifier
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface CharacterConverter {
}

@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface ToUpper {
}

@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface ToLower {
}
```

## アノテーションの付与
マッピングロジックに作成したアノテーションを付与する。

```java
@CharacterConverter
public class Characters {

    @ToUpper
    public String upperCase(String string) {
        return (string == null) ? null : string.toUpperCase();
    }

    @ToLower
    public String lowerCase(String string) {
        return (string == null) ? null : string.toLowerCase();
    }
}
```

## Mapperの作成

```java
@Mapper(uses = Characters.class) // (1)
public interface HogeFugaMapper {
    HogeFugaMapper INSTANCE = Mappers.getMapper(HogeFugaMapper.class);

    @Mapping(target = "hoge1", source = "fuga1", qualifiedBy = { CharacterConverter.class, ToUpper.class }) // (2)
    @Mapping(target = "hoge2", source = "fuga2", qualifiedBy = { CharacterConverter.class, ToLower.class }) // (3)
    Hoge fugaToHoge(Fuga fuga);
}
```

(1) マッピングロジッククラスを指定する
(2)(3) `qualifiedBy` 属性にマッピングロジッククラスのクラスレベルと、メソッドレベルに指定したアノテーションを指定する。

## 実行

```java
Fuga fuga = new Fuga("abc", "XYZ");
Hoge hoge = HogeFugaMapper.INSTANCE.fugaToHoge(fuga);

System.out.println(hoge.getHoge1()); // ABC
System.out.println(hoge.getHoge2()); // xyz
```

続きは次回。