結論
ecuacion-lib-validation と言うライブラリの @TrueWhen などの validator では、「別の項目の値が正規表現に合致する場合」にのみ Jakarta Validation で検証する機能があります、と言うお話。
はじめに
携帯電話番号(070/080/090 で始まる番号)を登録したユーザーには SMS 通知への同意が必要だが、固定電話番号の場合は不要、なんてケースを想像してみます。
こういった、他の項目の値によって条件が変わるチェック、service クラスに if 文を連ねる代わりに、validator でサクッと実装してみませんか?
@TrueWhen
ecuacion-lib-validation というlibraryの @XxxWhen にはこの機能があります。
ここでは @TrueWhen を使用します。
こんな形で指定します。
@TrueWhen(propertyPath = "smsConsentAgreed", conditionPropertyPath = "phone",
conditionValue = ConditionValue.PATTERN, conditionValuePatternRegexp = "^(070|080|090).*",
conditionValuePatternDescription = "携帯電話番号")
public record UserContact(String phone, boolean smsConsentAgreed) {
}
propertyPath という名称は、Jakarta Validation において field を特定する記述方法を表します。普通に field 名を書けばOKです。
見れば大体わかるとは思いますが一応説明すると、、、そもそもが英語なので英語で^^;
propertyPath (= smsConsentAgreed) is True When conditionPropertyPath (= phone) matches conditionValue (= PATTERN) conditionValueRegexp (= ^(070|080|090).*).
phone が ^(070|080|090).* という正規表現に合致する(= 携帯電話番号)ときだけ、smsConsentAgreed が true であることを検証するよ、と言うことですね。
conditionValuePatternDescription は省略可能ですが、設定するとエラーメッセージ中で正規表現の代わりに人間が読みやすい説明文を表示できます。
ecuacion-lib-validation の導入方法
導入方法については下記記事をご参照ください。
基本的な使い方
validation 対象として、まずはこちらの UserContactWithMessage.java を使用します。
@TrueWhen(propertyPath = "smsConsentAgreed", conditionPropertyPath = "phone",
conditionValue = ConditionValue.PATTERN, conditionValuePatternRegexp = "^(070|080|090).*",
message = "携帯電話番号の場合はSMS通知への同意が必要です。")
public record UserContactWithMessage(String phone, boolean smsConsentAgreed) {
}
そして、validation を実行する側のコードはこちら。
以下メソッドは単純に main メソッドから呼び出しています。以下同様。
private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
public static void 基本的な使い方() {
UserContactWithMessage info = new UserContactWithMessage("090-1234-5678", false);
var set = validator.validate(info);
for (ConstraintViolation<?> v : set) {
System.out.println(v.getMessage());
}
}
phone が "090-1234-5678" なので正規表現 ^(070|080|090).* に合致し、smsConsentAgreed が true かどうかチェックされます。ここでは false なのでエラーになります。これを実行すると以下のメッセージが出力されます。
携帯電話番号の場合はSMS通知への同意が必要です。
conditionValuePatternDescription の使用
conditionValuePatternDescription パラメータを使用すると、ExceptionUtil によるメッセージ出力で正規表現の代わりに人間が読みやすい説明文を表示できます。
@TrueWhen(propertyPath = "smsConsentAgreed", conditionPropertyPath = "phone",
conditionValue = ConditionValue.PATTERN, conditionValuePatternRegexp = "^(070|080|090).*",
conditionValuePatternDescription = "携帯電話番号")
public record UserContact(String phone, boolean smsConsentAgreed) {
}
public static void conditionValuePatternDescriptionの使用() {
UserContact info = new UserContact("090-1234-5678", false);
Set<ConstraintViolation<UserContact>> set = validator.validate(info);
for (String message : ExceptionUtil.getMessageList(set)) {
System.out.println(message);
}
}
conditionValuePatternDescription なしの場合、ExceptionUtil のデフォルトメッセージには正規表現がそのまま表示されます。
「userContact.phone」が「^(070|080|090).*」に合致する場合はtrue(選択済み)である必要があります
conditionValuePatternDescription を設定すると、正規表現の代わりに説明文が表示されます。
「userContact.phone」が「携帯電話番号」に合致する場合はtrue(選択済み)である必要があります
項目名を messages.properties または item_names.properties に記載すると、項目名も埋まります。
userContact.phone=電話番号
「電話番号」が「携帯電話番号」に合致する場合はtrue(選択済み)である必要があります
その他
その他の使用方法、when の条件、@TrueWhen 以外の validator の一覧などは、以下をご参照ください。
サンプルコード
サンプルコードは以下です。
https://github.com/ecuacion-jp/ecuacion-code-snippets/tree/main/ecuacion-lib-validation-TrueWhen
※このページから直接ソースの zip を download はできないと思うので、そのページにある ecuacion-code-snippets のリンクをクリックし、そこにある緑の <> Code ボタンから Download ZIP で download してください。
本サンプルのフォルダに移動後、mvn compile exec:java で実行できます。
まとめ
Jakarta Validation を使用し「別の項目の値が正規表現に合致する場合」のみ検証を実施する、@TrueWhen など @XxxWhen のご紹介でした。