spring ModelMapperでのマッピングでnull の無視や厳密なマッピングの設定

springでのアプリ開発で詰まったところをまとめていってます。
今回は、javaのorg.ModelMapperについてです。

# 1.この記事の内容
Bean同士のマッピングをしてくれるModelMapperで、
関係ないフィールドにもマッピングされたり、nullの値をマッピングさせない方法で少し躓いたので、まとめます。

# 2.そもそもModelMepperとは、、？
ModelMapperの役割的なことは、[こちらの記事](https://qiita.com/euledge/items/482a113589015590cf19#2-%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88)がわかりやすくまとめてくださっているので、読んでみてください。

簡単に要約すると、
・**違う型のBean(インスタンス）同士の値をコピーしてくれるものです。**


# ３. 違うフィールド名にも反映されてしまう
そんなModelMapperのぶち当たった課題
### 課題点
まず一つ目は、謎に他のフィールドにもマッピングされる問題。

私は、下記二つが、フィールドでマッピングさせたかったBeanです。
```java:BeanA.java
@Data
public class BeanA {
    private Integer hogehogeId;
    private Integer hogeId;
    private Integer fugaId;
    private String str;
}
```

```java:BeanB.java
@Data
public class BeanB {
    //'hogehogeId'のBeanBバージョンがない
    //他は同じフィールド名
    private Integer hogeId;
    private Integer fugaId;
    private String str;
}
```

この二つのBeanの違いは、hogehogeIdがあるかないかだけです。

データの中身としてはこんな感じです。
```json:BeanA
{
    "hogehoge_id": 111,
    "hoge_id": 222,
    "fuga_id": 333,
    "str": "text"
}
```
```json:BeanB
{
    "hoge_id": 999,
    "uga_id": null,
    "str": null
}
```

で、下記コードでマッピング処理をしました。
```java:MappinggService.java
@service
@RequiredArgsConstructor
public class MappingService {
    private final ModelMapper modelMapper;

public BeanA mapping() {
    //BeanA(destination)
    BeanA beanA = new BeanA();
    beanA.setHogehogeId(111);
    beanA.setHogeId(222);
    beanA.setFugaId(333);
    beanA.setStr("text");
    //BeanB(source)
    BeanB beanB = new BeanB();
    BeanB.setHogeId(999) //hogeIdだけセット
    //マッピング
    modelMapper.map(beanB, beanA);
    return beanA;
}
```

すると、結果がこうなりました。
```json:マッピング結果
{
    "hogehoge_id": 999,
    "hoge_id": 999,
    "fuga_id": null,
    "str": null
}
```
```json:マッピング理想
{
    "hogehoge_id": null,
    "hoge_id": 999,
    "fuga_id": null,
    "str": null
}
```
hogeIdだけが値がマッピングされて値が入ると思ったら、hogehogeIdにも同じ999がマッピングされていました。



### 解決方法
原因と考えられるのが、ModelMapperのデフォルトのConfigurationです。
config　の中に、**Matching strategy**（マッチング戦略?)というものがあって、
デフォルト値は`standard`で、結構曖昧なマッチング戦略になっています。

`hogeId`と`hogehogeId`が似てるからマッピングされたのでしょうか。


具体的な解決策は、
ModelMapperの`@Bean`アノテーションでのコンポーネントをspringコンテナに登録する際に、
このマッチング戦略の設定をしました。
```java:ModelMapperBean.java
public class ModelMapperBean{
    @Bean
    public ModelMapper modelMapper() {
		ModelMapper modelMapper = new ModelMapper();
        //マッチング戦略を厳しいものに設定
		modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
        //型の完全マッチなど
		modelMapper.getConfiguration().setFullTypeMatchingRequired(true);
		return modelMapper;
	}
}
```
この設定にすることで、理想通りのマッピングになりました。


# 4.nullもマッピングされてしまう
続いて、二つ目の課題ですが、
### 課題点
先ほどの、マッピング前後をもう一度お見せします。
```json:BeanA
{
    "hogehoge_id": 111,
    "hoge_id": 222,
    "fuga_id": 333,
    "str": "text"
}
```
```json:BeanB
{
    "hoge_id": 999,
    "uga_id": null,
    "str": null
}
```
マッピング↓
```json:マッピング結果
{
    "hogehoge_id": null,
    "hoge_id": 999,
    "fuga_id": null,
    "str": null
}
```
このnullです。
今回の要件的に、nullのものはマッピングを無視して、値がはいっているもののみをマッピングして、destenationに更新をかけるイメージでした。

しかし、当たり前ですが、sourceのnullをnullでdestinationにマッピングされてします。

いろいろ調べて、resource配下のapplication.yamlに
```yaml:application.yaml
modelmapper:
    skip-null-enabled: true
```
にすると、nullをコピーしない設定にできるとあったのですが、
なぜかうまくいきませんでした。

バージョンの問題かなと思ったりして、
[こちら](https://mvnrepository.com/artifact/org.modelmapper/modelmapper)を参考に、最新のバージョンに変えたりしたのですが、反映されず、、、
（原因わかっていません。思いつく方いらっしゃいましたら、ご教授ください。。）

### 解決策
これも、`課題１`の解決策と同様に、
ModelMapperのConfigurationに設定をすると解決しました。
あまり、　Beanの概念もわかっておらず、@Beanでのコンポーネント登録の際に、configもいじれることを知らなかったので、
課題１が解決した時に、もしやこの設定も！！？って感じに調べてみると、、
ありました！
```java:ModelMapperBean.java
public class ModelMapperBean{
    @Bean
    public ModelMapper modelMapper() {
		ModelMapper modelMapper = new ModelMapper();
        //nullをスキップする設定
		modelMapper.getConfiguration().setSkipNullEnabled(true);
		return modelMapper;
	}
}
```
この設定で、理想通りのマッピングがされました。
```json:マッピング結果
{
    "hogehoge_id": 111,
    "hoge_id": 999,
    "fuga_id": 333,
    "str": "text"
}
```
hoge_idだけがマッピングされました。

# 5.おわりに
他にも、いくつかconfig設定できるそうなので、この[リファレンス](http://modelmapper.org/user-manual/configuration/#matching-strategies)もご参考ください。

どちらも、期待通りの挙動にできてよかったです。
初歩的な躓きですが、どなたかの参考に参考になれば幸いです。

誤っている箇所などあれば、なんなりとご指摘いただきたく。。
ご朗読、ありがとうございました。