Spring で Bean Validation のエラーメッセージにフィールド名を埋め込む

エラーメッセージにフィールド名を埋め込む方法を調べたときのメモ。タイトルには Bean Validation と書いていますが、正確には Spring が提供する機能らしい。

調べたときのサンプルコードはこちら。

github.com


バリデーション用のアノテーションは以下の通り。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Constraint(validatedBy = { SampleValidator.class })
public @interface SampleValidation {

    String value();

    String message() default "{com.example.demo.constraint.SampleValidation.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}

今回は Controller で @Validated を利用してフォームバリデーションをするパターン。

@RestController
public class DemoController {

    @Autowired
    MessageSource messageSource;

    @PostMapping("index")
    public String index(@RequestBody @Validated FooForm form, Errors errors) {
        if (errors.hasErrors()) {
            errors.getAllErrors().stream()
                    .map(e -> messageSource.getMessage(e, Locale.getDefault()))
                    .forEach(System.out::println);
            return "NG";
        }
        return "OK";
    }

    static class FooForm {
        @SampleValidation("foo")
        private String name; // バリデーション対象のフィールド
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }

}

パターン1

フィールド名をプロパティに定義していない場合、フォームクラスのフィールド名がメッセージの {0} にそのまま出力される。

com.example.demo.constraint.SampleValidation.message={0} is invalid.

メッセージ出力は以下の通り。

name is invalid.

パターン2

フィールド名をキーにしてプロパティを定義した場合、定義したフィールド名がメッセージの {0} に埋め込まれて出力される。

com.example.demo.constraint.SampleValidation.message={0} is invalid.
name=Name

メッセージ出力は以下の通り。

Name is invalid.

パターン3

<フィールド名> 形式と <フォームクラス>.<フィールド名> 形式を一緒に定義した場合、<フォームクラス.フィールド名> 形式のプロパティが優先される。

com.example.demo.constraint.SampleValidation.message={0} is invalid.
name=Name
fooForm.name=NAME

メッセージ出力は以下の通り。

NAME is invalid.

現場からは以上です。