超簡単にJSPでenumを利用する方法

## 1. はじめに

Javaのenumは定数と異なりタイプセーフで、かつ、複数のデータを持つことが出来る便利なデータ型です。そのため、マスタなどのコードとその意味を一緒に定義することができます。
今回はJSPでそのenumを利用して、簡単にリストボックスやチェックボックスを表示する方法について説明したいと思います。
Webアプリはspring-boot(spring mvc、TERASOLUNA5.x)の前提とします。

## 2. enumの定義

今回のサンプルで利用するenumを定義します。intの`code`フィールドと表示する`label`フィールドのデータを持つenumとしました。
lombokを利用しない場合は明示的にコンストラクタとセッターも定義してください。

```java:Status.java
package com.example.demo;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum Status {

    APPROVAL(1, "承認"),
    DENIAL(2, "否認"),
    WITHDRAWAL(3, "取り下げ");

    int code;
    String label;

    // ★ポイント１
    public String getName() {
        return name();
    }
}
```

**★ポイント１**
enumは`name()`というメソッドを持っていますが、ゲッターとしてアクセスしたいため、ラップした`getName()`メソッドを定義します。
JSPでenumを利用するための対策です。

## 3. Formクラスの定義

入力されたデータを格納するFormクラスを定義します。

```java:DemoForm.java
public class DemoForm implements Serializable {

    // ★ポイント２
    @NotNull
    Status status;

    // ommited
}
```

**★ポイント２**
定義したenumをそのままフィールドとして定義します。intのコードやStringのラベルで受け取る必要はありません。enumはデータ型なので、このフィールドは必ず`Status`となります。
必須項目としたいのでBean Validationの`@NotNull`アノテーションを付与しました。

## 4. enumでリストボックスを出力するJSP

今回の記事のポイントであるenumでリストボックスを出力するJSPを作成します。
JSPの標準機能とspringの機能（`<form:xxx />`はspringのタグ）を利用します。

```xml:enumでリストボックスを出力するJSP
<%-- ★ポイント３ --%>
<%@ page import="com.example.demo.Status" %>

... 省略 ...

<%-- ★ポイント４ --%>
<form:errors path="status"/>
<form:select path="status" items="${Status.values()}" itemLabel="label" itemValue="name" />
```

**★ポイント３**
JSPで`Status`を参照したいため`<%@ page import="fqcn" %>`でクラスをインポートします。
JSPをスクリプトレットで記述していた時代はよく見かけましたが、最近はあまり見かけませんが、JSPの標準機能です。

**★ポイント４**
springの`<form:select />`タグを利用してリストボックスを出力します。属性が多いのでそれぞれについて以下で説明します。

| 属性 | 説明 |
|:----:|:----|
| `path`　| Formクラスの該当するフィールド名を指定します。今回は`status`になります。|
| `items`　| リストボックスに表示するデータを格納したコレクションや配列を指定します。<br>**ここでenumの`value()`スタティックメソッドを呼び出すのがポイントです。このメソッドはenumの配列を返します。**<br>これでenumの３項目を表示することができます。<br>★ポイント３で`Status`をインポートしたのは、このスタティックメソッドを呼び出すためです。|
| `itemLabel` | リストボックスの表示項目に利用するフィールドを指定します。<br>`今回はStatus`の`label`フィールドを表示したいので`label`を指定します。 |
| `itemValue` | リストボックスの値に利用するフィールドを指定します。**<br>`code`としたくなりますが、ここに`name`を指定するのがポイントです。**<br>レンダリングする際はゲッターを呼び出すことになるので、★ポイント１で定義した`getName()`メソッドが呼び出されることになります。|

## 5. 出力されるリストボックスのHTML

出力されるリストボックスのHTMLを以下に示します。
`<option>`の`value`属性にenumの`name`、表示項目には`label`が設定されます。
`value`が`Status`enumに定義されている`name`と一致する値の場合、特別な処理を行うことなくFormクラスにバインドすることが可能になります。

```html:出力されるHTML（見やすいように改行を追加）
<select id="status" name="status">
  <option value="APPROVAL">承認</option>
  <option value="DENIAL">否認</option>
  <option value="WITHDRAWAL">取り下げ</option>
</select>
```

`value`にenumに定義されていない値（ここでは`HOGE`）を設定した場合、以下のようにTypeMismatchのエラーとなります。
HTMLのフォームを改ざんしてvalueに不正な値を設定した場合や、★ポイント４の`itemValue`で誤って`code`フィールドを設定した場合などに発生します。

```text:変換できない値を設定してHTTPリクエストした場合
Failed to convert property value of type java.lang.String to required type com.example.demo.Status for property status; 
nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] 
to type [com.example.demo.Status] for value HOGE; nested exception is java.lang.IllegalArgumentException: No enum constant com.example.demo.Status.HOGE
```

**ここまでの説明で分かるようにJSPでもenumを利用することで、特別な入力チェックを用意することなく、Formに設定される時点でenumのタイプセーフが適用されます。**


## 6. enumでチェックボックスを出力するJSP

Formクラスは複数選択できるように配列に変更します。

```java:DemoForm.java
public class DemoForm implements Serializable {

    @NotNull
    @Size(min = 1, max = 3)
    Status[] status;
    // ommited
}
```

リストボックスを出力する際は`<form:select />`タグを利用しましたが、チェックボックスの場合は`<form:checkboxes />`タグを利用します。
チェックボックスを１つ出力する`<form:checkbox />`タグもあるので注意してください。

```xml:enumでチェックボックスを出力するJSP
<%-- ★ポイント５ --%>
<form:errors path="status"/>
<ul>
  <form:checkboxes path="status" items="${Status.values()}" 
      itemLabel="label" itemValue="name" element="li" />
</ul>
```

**★ポイント５**
リストボックスと異なる`element`属性について説明します。
これは出力するチェックボックスをラップするHTML要素を指定したい場合に設定します。
今回`は<ul><li>`を利用して一覧形式にしようと思い`li`を設定しました。

## 7. 出力されるチェックボックスのHTML

出力されるチェックボックスのHTMLを以下に示します。
チェックボックスのインプットフォームが`<li>`タグでラップされています。

```html:出力されるHTML（見やすいように改行を追加）
<ul>
  <li><input id="status1" name="status" type="checkbox" value="APPROVAL"/><label for="status1">承認</label></li>
  <li><input id="status2" name="status" type="checkbox" value="DENIAL"/><label for="status2">否認</label></li>
  <li><input id="status3" name="status" type="checkbox" value="WITHDRAWAL"/><label for="status3">取り下げ</label></li>
  <input type="hidden" name="_status" value="on"/>
</ul>
```

## 8. さいごに

今回はJSPでそのenumを利用して、簡単にリストボックスやチェックボックスを表示する方法について説明しました。
今回の方法ではenumの定義を変更してもJSPもFormも修正する必要がありません。
enumを定義する際に`getName()`メソッドを定義するという対策が必要ですが、特別な処理を実装することなく、フォームの入力値を簡単にenumにバインドすることができました。
ぜひJSPでもenumを利用してみてください。