結論
ecuacion-lib-validation の Violations クラスを使うと、Jakarta Validation の validation コードをメソッドチェーンでシンプルに書けます、というお話。
はじめに
ecuacion-lib-validation ではメッセージのカスタマイズに Violations.newMessageParameters() と ConstraintViolationExceptionWithParameters を使用します。
例えば、パラメータなしでエラー時に例外をスローする場合のコードはこちら。
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
var constraintViolations = validator.validate(form);
if (constraintViolations.size() > 0) {
throw new ConstraintViolationException(constraintViolations);
}
これはそれほど問題ないですが、メッセージパラメータを指定したい場合はこうなります。
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
var params = Violations.newMessageParameters().isMessageWithItemName(true);
var constraintViolations = validator.validate(form);
if (constraintViolations.size() > 0) {
throw new ConstraintViolationExceptionWithParameters(constraintViolations, params);
}
これが毎回あちこちに書かれると、少々冗長に感じますね。
Violations クラスの使い方
ecuacion-lib-validation の導入方法
導入方法については下記記事をご参照ください。
パラメータなし(基本形)
冒頭の4行のコードが、こう書けます。
new Violations().addAll(validator.validate(form)).throwIfAny();
new Violations() でオブジェクトを生成、addAll で validate の結果を追加、throwIfAny でエラーがあれば例外をスローします。
メッセージパラメータを指定する場合
メッセージパラメータを指定したい場合は、withMessageParameters を使用します。
new Violations().addAll(validator.validate(form))
.withMessageParameters(p -> p.isMessageWithItemName(true))
.throwIfAny();
withMessageParameters の引数はラムダ式で MessageParameters を操作します。複数のパラメータも連鎖して書けます。
new Violations().addAll(validator.validate(form))
.withMessageParameters(p -> p
.isMessageWithItemName(true)
.messagePrefix("アップロードしたエクセルファイルにおいて、"))
.throwIfAny();
BusinessViolation との併用
Violations クラスは、Jakarta Validation の ConstraintViolation だけでなく、BusinessViolation(ビジネスロジック上のエラー)も同じオブジェクトにまとめて扱えます。
BusinessViolation は、「このメールアドレスはすでに登録済みです」のような、入力形式ではなくビジネスルール上のエラーを表すクラスです。
Violations violations = new Violations()
.addAll(validator.validate(form));
// ビジネスロジックのチェック
if (accountRepository.existsByEmail(form.email())) {
violations.add(new BusinessViolation("このメールアドレスはすでに登録済みです。"));
}
violations.throwIfAny();
Jakarta Validation のエラーとビジネスロジックのエラーを1つの Violations にまとめてから一括で throwIfAny できるので、ExceptionHandler 側での処理も統一できます。
まとめ
Violations クラスを使うと、validation のコードがメソッドチェーンでスッキリ書けます。
| パターン | 通常の書き方 |
Violations を使った書き方 |
|---|---|---|
| パラメータなし | validate → サイズチェック → throw | new Violations().addAll(...).throwIfAny() |
| パラメータあり | params 生成 → validate → サイズチェック → throw | new Violations().addAll(...).withMessageParameters(...).throwIfAny() |