/vo-binding-validation

example to describe how to bind Value Object to request parameters and validation

Primary LanguageJavaApache License 2.0Apache-2.0

vo-binding-validation

値オブジェクトを不変オブジェクトのまま、formバインディングとバリデーションをStringのような組み込み型のようなものとして使えるようにする。

問題というか好み

  • Direct Field Accessを利用して、username.valueなどのようにするのもいいが、デフォルトコンストラクタが必須になる。利用する時にどれを使えば良いのか悩むのが嫌。
  • templateにusername.valueなんかが出るのが嫌。
  • 様々な状況でformのプロパティが必須でないか必須であるかは変化する。Formを変えたり、group機能を使ってvalidationをグループ化したい。

多少面倒だが、許容範囲となる方法と思うのでやって見た。

validation

  • 独自Validationとして@ValueObjectアノテーションを作成。Validator内部でValidationを実行し、その結果を出力

binding

  • ConditionalGenericConverterを実装したConverterを作成。@ValueObjectアノテーションに値オブジェクトの「コンストラクタ引数の型」 付与して、コンストラクタを使って文字列から値オブジェクトを生成。
  • 空文字からnullにConverter内で変換。
  • 「コンストラクタ引数の型」毎にConverterFactoryを作成(これは面倒い)

制約

  • 引数一つのコンストラクタを持つ値オブジェクトだけが対象
  • 値オブジェクトにはtoStringはそのまま入力値として表示させるようにオーバーライド必須。値オブジェクトを不変オブジェクトのまま、formバインディングとバリデーションをStringのような組み込み型のようなものとして使えるようにする。

利用例

Formクラス

package com.deffence1776.example.presentation;
import com.deffence1776.example.domain.Age;
import com.deffence1776.example.domain.Username;
import com.deffence1776.example.fw.validations.ValueObject;
import javax.validation.constraints.NotNull;

public class SampleForm {

    @ValueObject(emptyToNull = false)
    Username username;

    @ValueObject(parameterType = Integer.class,emptyToNull = true)
    @NotNull
    Age age;

    //setter getterは省略
    
}

テンプレート

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>フォーム</title>
</head>
<body>
<span  th:text="${msg}">msg</span>

<form action="#" th:action="@{/}" th:object="${sampleForm}" method="post">
    <label for="username">ユーザー名</label>
    <input  id="username" type="text"  th:field="*{username}"  >
    <span th:if="${#fields.hasErrors('username')}" th:errors="*{username}">username error</span>
    <br/>
    <label for="age">年齢</label>
    <input  id="age" type="text"  th:field="*{age}"  >
    <span th:if="${#fields.hasErrors('age')}" th:errors="*{age}">age error</span>
    <input type="submit" value="送信">
</form>
</body>
</html>