読者です 読者をやめる 読者になる 読者になる

SpringでResponseBodyとInterceptorの併用でハマった話

thymeleafネタと思った?残念Springちゃんでした!
すごい初歩的で恥ずかしい話なんですけど自戒をこめつつ。


Springを使ってJSONを返す場合、スタンダードな方法としてjacksonを使用する方法があります。
今回もこれを使った前提のお話なんですが、事象としてはControllerのメソッドにResponseBodyを指定したら500エラーが発生するというものです。


クラスパスにjackson-coreとjackson-mapperを通してxmlmvc:annotation-drivenとか書いてControllerのメソッドにResponseBody指定して終了のはずだったんですが、実際に叩いてみると何故か500エラーが返ってくる。
なになになんなのバグなの他のプロジェクトでも同じ方法でやってたよこんなの絶対におかしいよと頭を捻りつつソースを眺める。

       |
   \  __  /
   _ (m) _ピコーン
      |ミ|
    /  `´  \
     ('A`)
     ノヽノヽ
       くく


Interceptor…!Interceptorじゃないか…!

public class TestInterceptor implements HandlerInterceptor {
	@Override
	public void postHandle(HttpServletRequest req, HttpServletResponse res, Object obj,
			ModelAndView mav) throws Exception {
		mav.addObject("hoge", "piyo");
	}
(略)
}


ModelAndViewのnullチェック漏れてる…!

public class TestInterceptor implements HandlerInterceptor {
	@Override
	public void postHandle(HttpServletRequest req, HttpServletResponse res, Object obj,
			ModelAndView mav) throws Exception {
		if (mav != null) {
			mav.addObject("hoge", "piyo");
		}
	}
(略)
}


直った…しにたい…。


mvc:annotation-drivenを定義しておくとHandlerAdapterにはAnnotationMethodHandlerAdapterが使用されます。
処理の流れとしてはざっくり以下のような感じ。

  1. DispatcherServletがリクエストを受ける
  2. AnnotationMethodHandlerAdapterのhandleメソッドを実行
  3. ResponseBodyアノテーションが使用されているか調べ、使用されている場合はhandleResponseBodyメソッドを実行してnullを返す
  4. DispatcherServletに戻り、Interceptorが存在すれば各InterceptorのpostHandleを実行


ResponceBodyを使用せずに純粋にModelAndViewを返す場合は3つ目でModelAndViewが返って4つ目で特に問題も無く処理が通りますが、今回はnullを返してるので死んでた感じです。
ログはinfo以上を出力していたものの、ここのログの出力レベルはdebugなのでログに出なくてぱっと分からなかったのがまたアレ。
nullチェックと使用フレームワークのソースの確認はちゃんとしないとしぬ。

スポンサーリンク