結論
ecuacion-lib-validation では、Item#itemNameKey(String) または @ItemNameKeyClass を使うことで、メッセージに表示される項目名のキーをカスタマイズできます、というお話。
はじめに
ecuacion-lib-validation の ExceptionUtil.getMessageList でメッセージを生成する際、項目名は messages.properties または item_names.properties のキーで管理します。
デフォルトでは、クラス名(アンキャピタライズ)とフィールド名を . でつないだキーが使用されます。
例えば OrderForm クラスの productCode フィールドであれば orderForm.productCode というキーになります。
orderForm.productCode=商品コード
これで十分な場面も多いのですが、「フィールド名は productCode だけど、メッセージには 商品名 と表示したい」というケースが出てきます。
ecuacion-lib-validation では、Item と ItemContainer の仕組みでこれを解決できます。
ecuacion-lib-validation の導入方法
導入方法については下記記事をご参照ください。
ItemContainer の実装
項目名をカスタマイズするには、対象のクラスに ItemContainer インターフェースを実装します。
public record OrderForm(@NotEmpty String productCode, @NotNull Integer qty)
implements ItemContainer {
@Override
public Item[] customizedItems() {
return new Item[] {new Item("productCode").itemNameKey("productName")};
}
}
customizedItems() に、カスタマイズしたい項目を Item オブジェクトの配列で返します。
Item オブジェクトの取得は、ItemContainer#getItem を使用します。ただし customizedItems() 内では new Item(...) で定義し、実際の利用は getItem 経由で行われます。
Item#itemNameKey(String) の使い方
ドットなし:フィールド部分だけ変更
itemNameKey の引数に . を含まない文字列を渡した場合、フィールド部分だけが変更され、クラス部分はデフォルト(クラス名のアンキャピタライズ)が使用されます。
public record OrderForm(@NotEmpty String productCode, @NotNull Integer qty)
implements ItemContainer {
@Override
public Item[] customizedItems() {
return new Item[] {new Item("productCode").itemNameKey("productName")};
}
}
getItem("productCode").getItemNameKey(form) で解決後のキーを確認できます。
public static void itemNameKeyの使用_ドットなし() {
OrderForm form = new OrderForm(null, null);
System.out.println("getItem: " + form.getItem("productCode").getItemNameKey(form));
try {
MessageParameters params = ValidationUtil.messageParameters().isMessageWithItemName(true);
ValidationUtil.validateThenThrow(form, params);
} catch (ConstraintViolationException ex) {
for (String message : ExceptionUtil.getMessageList(ex, false)) {
System.out.println(message);
}
}
}
messages.properties に以下を定義します。
orderForm.productName=商品名
orderForm.qty=数量
getItem: orderForm.productName
「商品名」は入力必須です。
「数量」は入力必須です。
productCode フィールドのキーが orderForm.productCode から orderForm.productName に変わりました。クラス部分 orderForm はそのままで、フィールド部分だけが productName に変わっています。
ドットあり:クラス部分も明示指定
itemNameKey の引数に . を含む文字列を渡した場合、クラス部分とフィールド部分の両方が明示指定されます。
public record OrderFormWithDot(@NotEmpty String productCode, @NotNull Integer qty)
implements ItemContainer {
@Override
public Item[] customizedItems() {
return new Item[] {new Item("productCode").itemNameKey("product.name")};
}
}
public static void itemNameKeyの使用_ドットあり() {
OrderFormWithDot form = new OrderFormWithDot(null, null);
System.out.println("getItem: " + form.getItem("productCode").getItemNameKey(form));
try {
MessageParameters params = ValidationUtil.messageParameters().isMessageWithItemName(true);
ValidationUtil.validateThenThrow(form, params);
} catch (ConstraintViolationException ex) {
for (String message : ExceptionUtil.getMessageList(ex, false)) {
System.out.println(message);
}
}
}
messages.properties に以下を定義します。
product.name=商品名
orderFormWithDot.qty=数量
getItem: product.name
「数量」は入力必須です。
「商品名」は入力必須です。
キーが product.name となり、クラス名に依存しない完全な指定になっています。
「商品」エンティティ共通の定義(product.name=商品名)を複数の form クラスから参照したい場合などに有効です。
まとめ:ドットなし vs ドットあり
| 指定例 | クラス部分 | フィールド部分 | 解決後のキー |
|---|---|---|---|
itemNameKey("productName") |
クラス名から自動 (orderForm) |
productName |
orderForm.productName |
itemNameKey("product.name") |
明示指定 (product) |
name |
product.name |
@ItemNameKeyClass の使い方
@ItemNameKeyClass はクラスに付加するアノテーションで、そのクラス全フィールドのデフォルトのクラス部分を上書きします。
クラス名が長い、またはデフォルトのクラス名がキーとして適切でない場合に有効です。
@ItemNameKeyClass("order")
public record OrderFormWithAnnotation(@NotEmpty String productCode, @NotNull Integer qty)
implements ItemContainer {
@Override
public Item[] customizedItems() {
return new Item[] {};
}
}
public static void ItemNameKeyClassの使用() {
OrderFormWithAnnotation form = new OrderFormWithAnnotation(null, null);
System.out.println("getItem: " + form.getItem("productCode").getItemNameKey(form));
try {
MessageParameters params = ValidationUtil.messageParameters().isMessageWithItemName(true);
ValidationUtil.validateThenThrow(form, params);
} catch (ConstraintViolationException ex) {
for (String message : ExceptionUtil.getMessageList(ex, false)) {
System.out.println(message);
}
}
}
messages.properties に以下を定義します。
order.productCode=商品コード
order.qty=数量
getItem: order.productCode
「商品コード」は入力必須です。
「数量」は入力必須です。
OrderFormWithAnnotation のクラス名由来の orderFormWithAnnotation ではなく、order がクラス部分として使われました。
@ItemNameKeyClass はクラス全体のデフォルトを変えるものです。個別フィールドの itemNameKey 指定が優先されます。
サンプルコード
サンプルコードは以下です。
https://github.com/ecuacion-jp/ecuacion-code-snippets/tree/main/ecuacion-lib-core-JakartaValidationItemNameKey
※このページから直接ソースの zip を download はできないと思うので、そのページにある ecuacion-code-snippets のリンクをクリックし、そこにある緑の <> Code ボタンから Download ZIP で download してください。
本サンプルのフォルダに移動後、mvn compile exec:java で実行できます。
まとめ
ecuacion-lib-validation でメッセージの項目名をカスタマイズする2つの方法のご紹介でした。
| 方法 | 用途 |
|---|---|
itemNameKey("fieldOnly") |
フィールド部分だけ変更、クラス部分はデフォルト |
itemNameKey("class.field") |
クラス部分とフィールド部分を両方明示指定 |
@ItemNameKeyClass("className") |
クラス全体のデフォルトクラス部分を変更 |