Spring Boot Bean Validationでバリデーションエラーを短絡する
Spring BootにおけるBean Validationでは HibernateValidator
がデフォルトで利用される。
例えば以下のように @Validated
アノテーションを付与することでリクエストボディのバリデーションも行うことができ、このバリデーションにも HibernateValidator
が適用されることになる。
@PostMapping("...") public void post( ... @RequestBody @Validated XXX requestBody ) { ... }
しかし、このリクエストボディのバリデーションはデフォルトの挙動で全てのバリデーションエラーを BindingResult
として報告する。
つまり、1万件のバリデーションエラーを含むリクエストボディが送信された場合には、1万件全てのバリデーションエラーを検出した上で BindException
や ConstraintViolationException
を報告することになる。
これはメモリ/CPU上のパフォーマンス上の問題点を抱えている。 バリデーションエラーが高々数十件程度であれば問題ないが、上限の推測が難しい場合には全てのバリデーションエラーを報告するのではなく、最初のエラーが確認できた時点で処理を短絡させてしまいたい。
Hibernate Validatorのfail fast mode
そのようなユースケースで、Hibernate Validatorはfail fast modeを提供している。このモードを有効化している場合、最初にバリデーションエラーが報告された時点でバリデーション処理を中断させ、エラーとする。
Hibernate Validator Configurationの hibernate.validator.fail_fast
フラグをtrueに設定すれば良いのだが、Spring Bootでこの設定を行う方法は以下のように LocalValidatorFactoryBean
を自身で作成し、Auto Configurationで設定されるものを上書きすれば良い。
@Bean public LocalValidatorFactoryBean validatorFactory() { LocalValidatorFactoryBean validatorFactory = new LocalValidatorFactoryBean(); MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(); factoryBean.setMessageInterpolator(interpolatorFactory.getObject()); factoryBean.getValidationPropertyMap().put(HibernateValidatorConfiguration.FAIL_FAST, "true"); return validatorFactory; }
- 補足
Spring Bootの
ValidationAutoConfiguration
でAuto ConfigurationされているBeanは、既にValidator.class
のBeanが存在する場合には初期化されないため、自前で定義したLocalValidatorFactoryBean
の設定が利用されるようになる。 - spring-boot/ValidationAutoConfiguration.java at main · spring-projects/spring-boot · GitHub
LocalValidatorFactoryBean
の保持するvalidationPropertyMapにプロパティを追加すると以下の箇所で設定が読み込まれる。