Spring Boot で 例外ハンドリング
Spring Boot での例外ハンドリングの方法について調べたので、そのメモです。
*1
実際に試していないので、問題なく動作するのかはわからないですが、 http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc の内容でほぼ足りそうです。
例外に直接 HTTP Status を紐付けてしまう (Using HTTP Status Codes)
例外クラスに @ResponseStatus をつけることで、Spring MVC の方で処理してくれるっぽいです。
@ResponseStatus(value = NOT_FOUND, reason = "Resource is not found.") public class ResourceNotFoundException extends RuntimeException { ... }
しかし、これだとエラーレスポンスのボディに JSON で詳細情報を返すのはできなさそう……
Controller クラスごとに例外ハンドリング (Controller Based Exception Handling)
いままで Spring MVC で普通にやっていたのと同じように、Controller クラス内に @ExceptionHandler のついた例外ハンドリングのメソッドを用意するだけです。
@Controller public class FooController { // こんな感じ @ExceptionHandler @ResponseStatus(NOT_FOUND) public void notFound(ResourceNotFoundException ex) { // N/A } }
@ResponseBody もつければ、JSON 形式で詳細情報を返すことはできるはず。
しかし、この方法はシステム全体で共通のエラーハンドリングには向かない。
抽象親クラスつくるのはおすすめしない。というか、いまどき共通の機能を抽象親クラスにまとめるとか、ありえんでしょう……
(mix-in ならアリかも?java8ならインタフェースのデフォルト実装の機能を使うことで mix-in のようなことができるので、もしかしたらそれで出来るかも?)
システム全体での例外ハンドリング (Global Exception Handling)
@ControllerAdvice *2をつけたクラスを用意することで、すべての @Controller クラスに対する共通の設定を記述できる。
いってみたら、AspectJ で実装を Weaving するのに似ている。
@ControllerAdvice のクラスでは @ExceptionHandler, @InitBinder, @ModelAttribute アノテーションをつけた三種類のメソッドを定義できるらしい。
@ExceptionHandler だけでなく、@InitBinder も使えるのは嬉しい。空文字だったら null にしてしまうとか、そういうことが一箇所で済む。
@ControllerAdvice public class FooAdvice { @ExceptionHandler @RespnseStatus(NOT_FOUND) public void notFound(ResourceNotFoundException ex) { // N/A } }
これで、Controller の抽象親クラスを作るというアンチパターンから脱出できる……(といいな)
*1:たぶん、Spring Boot 関係ない。Spring MVC での話ですね……
*2:Spring 3.2 からサポートしていたらしい。 http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html