为啥将自定义 WrappedRequest 与额外的类型参数和 ActionFilter 组合会导致类型丢失?
Posted
技术标签:
【中文标题】为啥将自定义 WrappedRequest 与额外的类型参数和 ActionFilter 组合会导致类型丢失?【英文标题】:Why does combining a custom WrappedRequest with extra type parameter and ActionFilter cause the type to be lost?为什么将自定义 WrappedRequest 与额外的类型参数和 ActionFilter 组合会导致类型丢失? 【发布时间】:2016-01-06 15:49:31 【问题描述】:将可将请求转换为自定义 WrappedRequest
的 ActionBuilder
与附加类型参数组合,然后将其与 ActionFilter
组合会导致自定义 WrappedRequest
的类型被删除。
为什么会这样?有解决办法吗?
例如,假设我需要一个身份验证 ActionBuilder
和一个可选的授权 ActionFilter
,我们需要的用户类型可能会因使用情况而异。
查看这个人为的代码:
case class AuthRequest[A, U](val request: Request[A], val user: U) extends WrappedRequest[A](request)
case class TestUser(id: String)
case class AuthenticationAction[A]() extends ActionBuilder[(type λ[B] = AuthRequest[B, TestUser])#λ]
override def invokeBlock[A](request: Request[A], block: (AuthRequest[A, TestUser]) => Future[Result]): Future[Result] =
block(AuthRequest(request, TestUser("test-id")))
case class AuthorisedAction[A]() extends ActionFilter[(type λ[B] = AuthRequest[B, TestUser])#λ]
// does some additional authorisation checks for added security
def authorised(user: TestUser) = true
override def filter[A](request: AuthRequest[A, TestUser]) = Future.successful
if( authorised(request.user) ) None
else Some(Unauthorized)
请注意:上面的类型函数是this answer所必需的,因为AuthRequest
上有额外的类型参数。这也是必需的,因为此 API 将用于不止一种类型的用户。
如果我再实现一个使用上述内容的控制器:
class ExampleController extends Controller
def secured = (AuthenticationAction() andThen AuthorisedAction()) request =>
Ok(request.user.id)
我收到编译器错误 (value user is not a member of play.api.mvc.WrappedRequest[play.api.mvc.AnyContent]
)。也就是说,上面的变量request
的类型是WrappedRequest
,而不是预期的AuthRequest[play.api.mvc.AnyContent, TestUser]
的类型!
我了解大多数用例 AuthenticationAction
和 AuthorisedAction
将合并为一个操作,但由于授权是可选的,我希望将它们作为单独的关注点。
这可能吗?这是 Play Framework API 中的错误吗?还是 Scala 错误?还是人为错误?
【问题讨论】:
【参考方案1】:使用您的示例,我能够编写如下操作:
class ExampleController extends Controller
def secured = AuthorisedAction().compose(AuthenticationAction()) request =>
Ok(request.user.id)
有趣的是,在这两种情况下,IntelliJ 的类型检查都将request
视为AuthRequest[AnyContent, TestUser]
类型——只有scalac 将其视为WrappedRequest
。
【讨论】:
以上是关于为啥将自定义 WrappedRequest 与额外的类型参数和 ActionFilter 组合会导致类型丢失?的主要内容,如果未能解决你的问题,请参考以下文章
Java 9:将自定义模块化运行时映像与第三方插件系统相结合