3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spring BootでのBindingResult使用時に発生するIllegalStateExceptionの原因と解決方法

Posted at

はじめに

Spring Bootの開発環境で、フォームデータのバリデーションとエラーメッセージの表示を行う処理を実装中、BindingResultでバリデーション結果を保持するようにしたところ、IllegalStateExceptionが発生した件について、原因と解決方法をまとめました。

1.エラー内容

まず、実装内容について簡単に記載します。
以下のように、単項目のGETパラメータをInteger型で受け取り、BindingResultに結果を保持するよう実装していました。

SampleController.java
    @RequestMapping(value = {"/sample/"}, method = RequestMethod.GET)
    public String sampleComplete(@RequestParam(name = "sampleCode", required = false) Integer sampleCode, 
                                 BindingResult bindingResult, Model model) {
        // 実装
        return "/sample";
    }

しかし、実行したところ、以下のエラーが発生しました。

java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be declared immediately after the model attribute, 
the @RequestBody or the @RequestPart arguments to which they apply: public 
java.lang.String SampleController.sampleComplete(java.lang.Integer,
org.springframework.validation.BindingResult, org.springframework.ui.Model) 
throws java.lang.Exception

「BindingResult引数が対応するモデル属性、@RequestBodyなどの引数の直後に宣言されていない」という内容のエラーですが、SampleController.javaでは直後に宣言しているので、別の部分に原因がありそうです。

BindingResultは、バリデーションエラーを保持するためのものであり、対応する引数の直後に配置する必要があります。

2.原因

原因を調査したところ、以下の理由からBindingResult@RequestParamに対応していないことが分かりました。

BindingResultは、Formオブジェクトに対してバリデーション結果を保持するよう設計されている

つまり、複数フィールドをもつFormオブジェクトを引数とすべきところで、単一のリクエストパラメータを記載していたことが間違いだったようです。

@RequestParam:単一のリクエストパラメータをバインドするためのものであり、複数フィールドを持つオブジェクトのバインドには適していない

3.解決

解決方法は、2つあります。
①そもそもBindingResultは使わない
BindingResultを使用する場合は、単項目パラメータでもFormオブジェクトを作成する

①で解決も可能ですが、今回は他処理に合わせた仕様としたかったので、②の解決方法をとりました。
@ModelAttributeを使用して、IntegerではなくSampleFormというFormオブジェクトに格納するよう修正した結果が以下です。

SampleController.java
    @RequestMapping(value = {"/sample/"}, method = RequestMethod.GET)
    public String sampleComplete(@ModelAttribute SampleForm sampleForm,
                                 BindingResult bindingResult, Model model) {
        // 実装
        return "/sample";
    }

これで実行結果も問題なく、バリデーション結果が保持されていました!

あとがき

今回のエラーは、BindingResultがFormオブジェクトに対してバリデーション結果を保持するものであることを把握していなかったために発生しました。
知らずにこのエラーが発生してしまったという方の参考になれば幸いです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?