Spring-bootでRequestBodyのEnumをデシリアライズする

# 概要
EnumをメンバーにもったJavaBeanをRequestBodyとして送り
Controllerでデシリアライズされるところまでを試しました。

# 環境
※ Thymeleafが少し古いです

|Module|Version|
|---|---|
|spring-boot|1.5.1.RELEASE|
|thymeleaf|3.0.1.RELEASE|
|thymeleaf-layout-dialect|2.0.1|

# どうやったか
## Enumを作る
今回は`OFF/ON`定数を持ったFlagというEnumを作ります。
それぞれ数値フィールド`0/1`を定義しています。
また、数値フィールドの値から定数を判別メソッドも用意しています。

```java
public enum Flag {
    OFF(0),
    ON(1);

    private int value;

    Flag(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public static Flag parse(int value) {
        return Arrays.stream(Flag.values())
                .filter(flag -> flag.getValue() == value)
                .findFirst()
                .orElseGet(() -> Flag.OFF);
    }
}
```

## Modelを作る
前述のEnumをメンバーにもったModelです。

```java
public class Sample {
    private String hoge;
    private Long fuga;
    private Flag flag;

    // アクセサメソッドは省略
}
```

## Controllerを作る
作成したModelをRequestBodyとして受け取るControllerです。
`/`にGETアクセスすると後述のテンプレートを表示し、
`/log`にPOSTアクセスすると、RequestBodyの値を`System.out`しています。

```java
@Controller
@RequestMapping("/")
public class SampleController {
    @GetMapping
    public String index() {
        return "sample";
    }

    @PostMapping("log")
    public String log(@RequestBody Sample sample) {
        System.out.println("hoge = " + sample.getHoge());
        System.out.println("fuga = " + sample.getFuga());
        System.out.println("flag = " + sample.getFlag());

        return "redirect:sample";
    }
}
```

## Deserializerを作る
今回のメイン。Requestで受け取った値からObjectにデシリアライズする処理を書くところです。
受け取った値を実際にデシリアライズする処理を`com.fasterxml.jackson.databind.JsonDeserializer`を継承して作成します。

```java
class FlagDeserializer extends JsonDeserializer<Flag> {

    @Override
    public Flag deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException {
        final int jsonValue = jsonParser.getIntValue();
        return Flag.parse(jsonValue);
    }
}
```

そして作成したDeserializerをBeanとして定義します。

```java
@Configuration
public class JsonConfiguration {
    /**
     * JSON<->Enum間の変換Moduleを登録します
     * @return {@link ObjectMapper}
     */
    @Bean
    public ObjectMapper jsonObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(generateFlagModule());
        return mapper;
    }

    private Module generateFlagModule() {
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addDeserializer(Flag.class, new FlagDeserializer());
        return simpleModule;
    }
}
```

## テンプレートを作る
Requestを送るためだけのThymeleafテンプレートです。
ブラウザには`send`ボタンだけ表示されます。

```html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xml:lang="ja" lang="ja">
<head>
</head>
<body>
<input type="button" value="send" id="send" name="send">
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript">
    $(function () {
        $('#send').on('click', function () {
            $.ajax({
                type: 'post',
                url: '/log',
                data: JSON.stringify(
                        {
                            "hoge": "hoge",
                            "fuga": 123,
                            "flag": 1
                        }
                ),
                dataType: 'json',
                contentType: 'application/JSON',
                scriptCharset: 'utf-8'
            }).done(function (data) {
                console.log(data);
            });
        })
    });
</script>
</body>
</html>
```

# 結果
アプリを起動してブラウザで`send`ボタンを押すと、コンソールに次のように表示されます。

```
hoge = hoge
fuga = 123
flag = ON
```

# サンプルコード
ここに今回作成したサンプルを置いています。
https://github.com/panage/enum-serialize-demo