Scala Play 2.5 如何让视图可以访问 Java 的 Context/Session/Request?
Scala Play 2.5 How to make Java's Context/Session/Request accessible to a view?
我正在研究这个 Scala play-authenticate-usage-scala project where I build on top of a Java framework play-authenticate(我知道,生活并不完美......)。当 运行 应用程序时,我看到下面包含异常。
仔细检查堆栈跟踪,我找到了使用 forProviders.scala.html
模板的视图 views._providerPartial.scala.html
,该模板又使用依赖于 Java 的 Play 的 类 play.mvc.Http.{ Session, Context, etc}
因此,错误是因为我的示例应用程序带来了 Scala play.api.mvc._
。
我知道我可以用 Scala 做:
import play.core.j.JavaHelpers
val jContext : play.mvc.Http.Context = JavaHelpers.createJavaContext(request)
val jSession : play.mvc.Http.Session = context.session()
问题是我怎样才能让上面的这些隐式地提供给那个视图。
[error] application -
! @72ef8b5j8 - Internal server error, for (GET) [/login] ->
play.api.http.HttpErrorHandlerExceptions$$anon: Execution exception[[RuntimeException: There is no HTTP Context available from here.]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:293)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:220)
at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:100)
at play.core.server.netty.PlayRequestHandler$$anonfun$$anonfun$apply.applyOrElse(PlayRequestHandler.scala:100)
at play.core.server.netty.PlayRequestHandler$$anonfun$$anonfun$apply.applyOrElse(PlayRequestHandler.scala:99)
at scala.concurrent.Future$$anonfun$recoverWith.apply(Future.scala:346)
at scala.concurrent.Future$$anonfun$recoverWith.apply(Future.scala:345)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
Caused by: java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:62)
at play.mvc.Http$Context$Implicit.session(Http.java:330)
at com.feth.play.module.pa.views.html.forProviders_Scope0$forProviders$$anonfun$apply.apply(forProviders.template.scala:37)
at com.feth.play.module.pa.views.html.forProviders_Scope0$forProviders$$anonfun$apply.apply(forProviders.template.scala:35)
at play.twirl.api.TemplateMagic$.defining(TemplateMagic.scala:13)
at com.feth.play.module.pa.views.html.forProviders_Scope0$forProviders.apply(forProviders.template.scala:35)
at views.html._providerPartial_Scope0$_providerPartial.apply(_providerPartial.template.scala:38)
at views.html.login_Scope0$login_Scope1$login.apply(login.template.scala:74)
at controllers.Application$$anonfun$$anonfun$apply.apply(Application.scala:57)
at controllers.Application$$anonfun$$anonfun$apply.apply(Application.scala:57)
UPDATE 我尝试了以下但没有成功。基本上 Java 方期望所有这些都在 ThreadLocal
中。特定 ThreadLocal
实例公开位于 play.mvc.Http.Context.current
。因此,我准备了一个名为 _adaptScalaToJava.scala.html
的模板助手,如下所示:
@import be.objectify.deadbolt.scala._
@import play.core.j.JavaHelpers
@()(implicit request: AuthenticatedRequest[Any])
@play.mvc.Http.Context.current.set(JavaHelpers.createJavaContext(request))
直接设置当前线程中的jContext,用法如下:
@_adaptScalaToJava
@forProviders(playAuth, skipCurrent) { p =>
<li>
@if(p.getKey() == "openid") {
<a href="javascript:void(0);" onclick="askOpenID('@p.getUrl()');">
} else {
<a href="@p.getUrl()">
}
@_providerIcon(p.getKey())</a>
</li>
}
但即使编译发现它仍然会触发相同的异常...
在麻烦的代码前仅放置这一行即可解决问题:
@play.mvc.Http.Context.current.set(play.core.j.JavaHelpers.createJavaContext(request))
@forProviders(playAuth, skipCurrent) { p =>
试图让它更干净一点,即它不会一直重置,但我仍然是个谜,为什么这不起作用:
@if (play.mvc.Http.Context.current.get() == null) {
@play.mvc.Http.Context.current.set(play.core.j.JavaHelpers.
createJavaContext(request))
}
似乎 play.mvc.Http.Context.current
不是 null
...底线是我需要连接 IDE 并调试代码。
更新实际上这是官方的做法:
@play.core.j.JavaHelpers.withContext(request) { jContext =>
@forProviders(playAuth, skipCurrent) { p =>
...
}
}
我正在研究这个 Scala play-authenticate-usage-scala project where I build on top of a Java framework play-authenticate(我知道,生活并不完美......)。当 运行 应用程序时,我看到下面包含异常。
仔细检查堆栈跟踪,我找到了使用 forProviders.scala.html
模板的视图 views._providerPartial.scala.html
,该模板又使用依赖于 Java 的 Play 的 类 play.mvc.Http.{ Session, Context, etc}
因此,错误是因为我的示例应用程序带来了 Scala play.api.mvc._
。
我知道我可以用 Scala 做:
import play.core.j.JavaHelpers
val jContext : play.mvc.Http.Context = JavaHelpers.createJavaContext(request)
val jSession : play.mvc.Http.Session = context.session()
问题是我怎样才能让上面的这些隐式地提供给那个视图。
[error] application -
! @72ef8b5j8 - Internal server error, for (GET) [/login] ->
play.api.http.HttpErrorHandlerExceptions$$anon: Execution exception[[RuntimeException: There is no HTTP Context available from here.]]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:293)
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:220)
at play.api.GlobalSettings$class.onError(GlobalSettings.scala:160)
at play.api.DefaultGlobal$.onError(GlobalSettings.scala:188)
at play.api.http.GlobalSettingsHttpErrorHandler.onServerError(HttpErrorHandler.scala:100)
at play.core.server.netty.PlayRequestHandler$$anonfun$$anonfun$apply.applyOrElse(PlayRequestHandler.scala:100)
at play.core.server.netty.PlayRequestHandler$$anonfun$$anonfun$apply.applyOrElse(PlayRequestHandler.scala:99)
at scala.concurrent.Future$$anonfun$recoverWith.apply(Future.scala:346)
at scala.concurrent.Future$$anonfun$recoverWith.apply(Future.scala:345)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
Caused by: java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:62)
at play.mvc.Http$Context$Implicit.session(Http.java:330)
at com.feth.play.module.pa.views.html.forProviders_Scope0$forProviders$$anonfun$apply.apply(forProviders.template.scala:37)
at com.feth.play.module.pa.views.html.forProviders_Scope0$forProviders$$anonfun$apply.apply(forProviders.template.scala:35)
at play.twirl.api.TemplateMagic$.defining(TemplateMagic.scala:13)
at com.feth.play.module.pa.views.html.forProviders_Scope0$forProviders.apply(forProviders.template.scala:35)
at views.html._providerPartial_Scope0$_providerPartial.apply(_providerPartial.template.scala:38)
at views.html.login_Scope0$login_Scope1$login.apply(login.template.scala:74)
at controllers.Application$$anonfun$$anonfun$apply.apply(Application.scala:57)
at controllers.Application$$anonfun$$anonfun$apply.apply(Application.scala:57)
UPDATE 我尝试了以下但没有成功。基本上 Java 方期望所有这些都在 ThreadLocal
中。特定 ThreadLocal
实例公开位于 play.mvc.Http.Context.current
。因此,我准备了一个名为 _adaptScalaToJava.scala.html
的模板助手,如下所示:
@import be.objectify.deadbolt.scala._
@import play.core.j.JavaHelpers
@()(implicit request: AuthenticatedRequest[Any])
@play.mvc.Http.Context.current.set(JavaHelpers.createJavaContext(request))
直接设置当前线程中的jContext,用法如下:
@_adaptScalaToJava
@forProviders(playAuth, skipCurrent) { p =>
<li>
@if(p.getKey() == "openid") {
<a href="javascript:void(0);" onclick="askOpenID('@p.getUrl()');">
} else {
<a href="@p.getUrl()">
}
@_providerIcon(p.getKey())</a>
</li>
}
但即使编译发现它仍然会触发相同的异常...
在麻烦的代码前仅放置这一行即可解决问题:
@play.mvc.Http.Context.current.set(play.core.j.JavaHelpers.createJavaContext(request))
@forProviders(playAuth, skipCurrent) { p =>
试图让它更干净一点,即它不会一直重置,但我仍然是个谜,为什么这不起作用:
@if (play.mvc.Http.Context.current.get() == null) {
@play.mvc.Http.Context.current.set(play.core.j.JavaHelpers.
createJavaContext(request))
}
似乎 play.mvc.Http.Context.current
不是 null
...底线是我需要连接 IDE 并调试代码。
更新实际上这是官方的做法:
@play.core.j.JavaHelpers.withContext(request) { jContext =>
@forProviders(playAuth, skipCurrent) { p =>
...
}
}