Slim3でのsessionScopeでClassCastException

Slim3でModelがHOT reloadingに対応されたあたりから
sessionScopeでHttpSessionに格納した値を取得しようとした時に
ClassCastExceptionが発生するようになったので、
ちょっと調べてみた。


ClassCastException発生までの手順は以下
1.ログイン時のユーザ情報(mailアドレス等)をStringでHttpSessionに格納
2.複数回sessionScope(Stirng)を呼び出さないリクエストを実行
3.sessionScope(Stirng)を呼び出すリクエストを実行し、
  1で格納したStringを取得しようとするとClassCastException発生

 
java.lang.ClassCastException: org.slim3.controller.BytesHolder cannot be cast to java.lang.String
at jp.nextam.controller.AbstractController.getSei(AbstractController.java:154)
at jp.nextam.controller.AbstractController.getUserInfo(AbstractController.java:66)
at jp.nextam.controller.bug.IndexController.run(IndexController.java:36)
at org.slim3.controller.Controller.runBare(Controller.java:94)
at org.slim3.controller.FrontController.processController(FrontController.java:477)
at org.slim3.controller.FrontController.doFilterInternal(FrontController.java:299)
at org.slim3.controller.FrontController.doFilter(FrontController.java:258)
at org.slim3.controller.FrontController.doFilter(FrontController.java:225)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.slim3.jdo.JDOFilter.doFilter(JDOFilter.java:63)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.slim3.controller.HotReloadingFilter.doHotReloading(HotReloadingFilter.java:223)
at org.slim3.controller.HotReloadingFilter.doFilter(HotReloadingFilter.java:186)
at org.slim3.controller.HotReloadingFilter.doFilter(HotReloadingFilter.java:159)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:124)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:313)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)


詳細までコードを追っていないので、認識が正しいか自信がないが、
HOT reloadingが有効な場合、
HotReloadingFilter.doHotReloadingのfinallyで
Cleaner.cleanAll()が呼び出され、HotHttpSessionWrapperのclean()で
HttpSessionにsetAttributeされている値を、
org.slim3.controller.BytesHolderに変換して再格納している。
そして、リクエストでsessionScopeでアクセスした際に、再度
org.slim3.controller.BytesHolderを格納時の型(今回の場合はString)に変換して取得される。


そのため、リクエスト毎にsessionScope(Stirng)を呼び出せば型が都度変換されるため
問題なく取得できるが、sessionScope(Stirng)を呼び出さないリクエストを呼び出した場合、
HotHttpSessionWrapperのcleanメソッドで、BytesHolderに変換されたものをさらに
BytesHolderに変換して再格納するため、次のリクエストで取得する時に
元の型に戻そうとしてもBytesHolderになってしまい、
ClassCastExceptionが発生するっぽい。


なんか、書いてて分かりづらい説明になってしまったが、
回避策としては、リクエストの都度sessionScopeで取得すれば良いので
とりあえずは、それで回避するとしよう。