⛄️
BeanValidationの相関バリデーションとそもそもの話
"BeanValidationで相関バリデーションするときに新しいメソッド作って@AssertTrue
を使うよ!"っていう話があったので、それについて思う事を書きます。
なお、以下はWebアプリケーションでリクエストパラメータをPOJOにマッピングしてBeanValidationを行うという流れを想定しています。
@AssertTrueでバリデーション
件の相関バリデーションはたぶんこんな感じです。
public int from;
public int to;
@AssertTrue
public boolean isFromLessThanTo() {
return from < to;
}
私は、これは
- メソッド内にバリデーションロジックを書くので再利用性が低い
-
@AssertTrue
、そしてboolean
は宣言的ではない
と思っています。
じゃあ、どうすればいいのか
from < to
を検証するアノテーションとカスタムバリデータを作りましょう。
そしてそれを付けるメソッドはboolean
ではなくタプル(のような何か)を返します。
public int from;
public int to;
@FromLessThanTo
public Pair isFromLessThanTo() {
return new Pair(from, to);
}
こうする事で、
- バリデーションのロジックはカスタムバリデータに閉じ込めたので再利用性高まる
- アノテーションで大小関係があるって分かって宣言的っぽい
となるかと。
そもそも
アノテーションを使ったバリデーションってどうなんでしょうね?
例えば、次のようなコードがあったとします。
@Isbn
public String isbn1;
@Isbn
public String isbn2;
アノテーションを見ればisbn1
もisbn2
もISBNであるということは分かるのですが、でもそれってアノテーションの役割じゃなくて型じゃないの?と思うのです。
本来あるべき姿はこんな感じ。
public Isbn isbn1;
public Isbn isbn2;
この場合バリデーションはIsbn型へ変換するときに行うのが良いと思われます。
型よ
基本的にバリデーションは次の順番で行われると思います。
- 必須バリデーション
- フォーマットバリデーション(日付とされる値が
yyyy/MM/dd
になっているか?みたいなことです) - 相関バリデーション
必須バリデーションを行うか否かも型で表したい。
Optional
でないものは必須!という感じです。たぶんそれが良いと思う。
//必須
public Isbn isbn1;
//必須でない
public Optional<Isbn> isbn2;
フォーマットも先述の通り型で表す事ができます。
それから相関バリデーションですが、最初の例であればRange
といった型を作ってそこにfrom
とto
を詰め込めばfrom
とto
の大小関係を型で表す事ができます。
new Range(from, to);
まとめ
まとまりません! もっと理想的なバリデーションフレームワークが欲しい!
というわけでバリデーションへの悩みは尽きません。 悩ましい。
Discussion