結論
ecuacion-lib-validation には、@Valid を使って子・孫オブジェクトを検証した場合に、「社員のノートPC」の「機種名」のように、どのオブジェクトに属する項目かを明示したメッセージを生成する機能があります、というお話。
はじめに
Jakarta Validation では、@Valid を使うと子・孫オブジェクトのフィールドまで再帰的に検証できます。
例えばこんな構成を考えてみます。
public record Employee(String name, @Valid Laptop laptop, @Valid CellPhone cellPhone) {
}
public record Laptop(@NotNull String model) {
}
public record CellPhone(@NotNull String model) {
}
Employee は Laptop(ノートPC)と CellPhone(携帯電話)を持っていて、どちらも model(機種名)フィールドを持っています。
何が問題になるのか
item_names.properties に項目名を登録する際、laptop.model に「機種名」と定義したとします。
laptop.model=機種名
cellPhone.model=機種名
Laptop 単体で検証するならこれで問題ありません。
「機種名」は入力必須です。
一方、Employee を検証した場合、ConstraintViolation の propertyPath は employee.laptop.model になります。
普通に Employee を検証してメッセージを出すと、同じメッセージが出力されます。
「機種名」は入力必須です。
どちらのオブジェクトの model がエラーなのか、これだけではわかりません。
Laptop と CellPhone のどちらも model フィールドを持っており、どちらもラベルは「機種名」。
これでは「どちらの機種名?」となってしまいます。
「社員のノートPC の」のような文言が必要
エラー内容をユーザに伝えるには、「社員のノートPC の機種名」のように、対象オブジェクトを特定できる文言が必要ですね。
ecuacion-lib-validation では、この問題を ValidationUtil.messageParameters().showsItemNamePath(true) で解決できます。
基本的な使い方
ecuacion-lib-validation の導入方法
導入方法については下記記事をご参照ください。
item_names.properties の定義
showsItemNamePath(true) を使う場合、propertyPath の末尾セグメントに加えて、その親パスの項目名も item_names.properties に定義します。
employee.laptop.model の場合:
- 親パス
employee.laptopに対してemployee.laptop=社員のノートPC - 末尾セグメントに対して
laptop.model=機種名
employee.laptop=社員のノートPC
employee.cellPhone=社員の携帯電話
laptop.model=機種名
cellPhone.model=機種名
検証コード
ValidationUtil.messageParameters().showsItemNamePath(true) を指定して検証します。
public static void showsItemNamePathの使い方() {
Employee employee = new Employee("山田太郎", new Laptop(null), new CellPhone(null));
try {
MessageParameters params = ValidationUtil.messageParameters()
.isMessageWithItemName(true)
.showsItemNamePath(true);
ValidationUtil.validateThenThrow(employee, params);
} catch (ConstraintViolationException ex) {
for (String message : ExceptionUtil.getMessageList(ex, false)) {
System.out.println(message);
}
}
}
出力結果はこちらです。
「社員の携帯電話」の「機種名」は入力必須です。
「社員のノートPC」の「機種名」は入力必須です。
親パスの項目名と末尾の項目名を の でつなげて表示してくれます。
「社員のノートPC の機種名」なのか「社員の携帯電話の機種名」なのか、明確にわかるようになりましたね。
サンプルコード
サンプルコードは以下です。
https://github.com/ecuacion-jp/ecuacion-code-snippets/tree/main/ecuacion-lib-validation-ValidChildObjectItemNamePath
※このページから直接ソースの zip を download はできないと思うので、そのページにある ecuacion-code-snippets のリンクをクリックし、そこにある緑の <> Code ボタンから Download ZIP で download してください。
本サンプルのフォルダに移動後、mvn compile exec:java で実行できます。
まとめ
@Valid で子・孫オブジェクトを検証した際、同名フィールドが複数存在するとメッセージだけでは対象を特定できなくなります。
ValidationUtil.messageParameters().showsItemNamePath(true) を使うことで、親パスの項目名と末尾の項目名を組み合わせたメッセージが生成でき、「どのオブジェクトの、どのフィールドのエラーか」がユーザに伝わるメッセージになります。