Spring MVCでは、リクエストパラメータをJava Bean(=フォームオブジェクト)にバインディングしてControllerのメソッドで受け取ることができ、リストや配列のプロパティについては、インデックス付き配列パラメータ(例:ids[0]
)を使用して値を設定する位置を明示的に指定することができます。
デフォルトの上限値
インデックス付き配列パラメータのデフォルトの上限値は256です。
以下に示すJava Beanにバインディングするとすれば・・・
public class SearchQuery {
private List<String> ids;
// ...
}
ids[0]
〜ids[255]
までが有効なパラメータで、ids[256]
は無効なパラメータとして扱われます。
Warning:
仕組み上は
int
の最大値(2147483647
)まで増やすことができますが、無闇に数を増やすとOutOfMemoryError
の発生リスクが増えるので注意しましょう。
上限値の変更
上限値は、org.springframework.web.bind.WebDataBinder
のsetAutoGrowCollectionLimit
メソッドを呼び出すことで変更することができます。具体的には、@InitBinder
メソッドを使用します。
@InitBinder
public void configureWebDataBinder(WebDataBinder binder){
binder.setAutoGrowCollectionLimit(512);
}
アプリケーション全体で上限値を変更したい場合は、@ControllerAdvice
を付与してクラスで上記メソッドを実装するのがよいでしょう。
Warning:
setAutoGrowCollectionLimit
メソッドを呼び出す前に、registerCustomEditor
やaddCustomFormatter
メソッドなどを呼び出してしまうと上限値の変更が無視される(無効なメソッド呼び出しになる)ので注意してください。なお、Spring 4.3.4までは無効なメソッド呼び出しを行ってもエラーになりませんが、2016/12/20リリース予定のSpring 4.3.5からはエラーになってくれます!!(SPR-14888)。
上限値を超えた時の動作
上限値を超えるインデックス付きパラメータが指定された場合は、無効なパラメータとして扱われ、デフォルトの動作ではシステムエラー(500: Internal Server Error)になります。
Note:
この動作は個人的にはバグなのでは?と思っており、クライアントエラー(400: Bad Request)として扱ってほしい!!というIssue(SPR-14874)を作成してみました。
エラーレスポンスのカスタマイズ
デフォルトの動作だと、上限値を超えるとシステムエラーになってしまいます。このケースは、クライアントからのリクエスト内容が間違っているのが原因なので、クライアントエラーとして扱いたいはずです。
上限値を超えるとorg.springframework.beans.InvalidPropertyException
が発生するため、@ExceptionHandler
メソッドでこの例外をハンドリングすればエラーレスポンスをカスタマイズすることができます。
@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleInvalidPropertyException(InvalidPropertyException e) {
logger.warn("detected an invalid request.", e);
return "Bad Request !!";
}
Warning:
InvalidPropertyException
は、上限値を超えた時以外にも発生する例外なので、作成するアプリケーションによっては、細かく例外ハンドリングする必要がでてくるかもしれません。
まとめ
おそらく、ほとんどのアプリケーションでデフォルト値(256
)がそのまま使えると思います。
以外に見落としがちなのが・・・インデックス付き配列パラメータを使う場合のエラーハンドリングだと思います。どうするのがベストプラクティスなのかはまだわかっていませんが、デフォルトだとシステムエラー扱いになってしまうことは意識しておくべきでしょう。