Чтобы добавить новый параметр в большое количество существующих конечных точек, я создал новый ActionRefiner
, который будет обрабатывать новый параметр и добавлять информацию для параметра в существующий запрос. Однако, когда я добавляю новый ActionRefiner
в цепочку ActionRefiners
в конечной точке, в результате получается ActionBuilder[WrappedRequest, AnyContent]
, что не позволяет мне получить доступ к данным, добавленным к запросам ActionRefiners
. Например,
import scala.concurrent.{ExecutionContext, Future}
import com.google.inject.Inject
import play.api.mvc._
// Base requests.
class IntRequest[A](val num: Int, request: Request[A]) extends WrappedRequest[A](request)
class CharRequest[A](val char: Char, request: Request[A]) extends WrappedRequest[A](request)
// Actions for creating base requests.
class IntAction @Inject()(val parser: BodyParsers.Default)(implicit val executionContext: ExecutionContext)
extends ActionBuilder[IntRequest, AnyContent]
with ActionTransformer[Request, IntRequest] {
override def transform[A](request: Request[A]): Future[IntRequest[A]] = {
Future.successful(new IntRequest[A](1, request))
}
}
class CharAction @Inject()(val parser: BodyParsers.Default)(implicit val executionContext: ExecutionContext)
extends ActionBuilder[CharRequest, AnyContent]
with ActionTransformer[Request, CharRequest] {
override def transform[A](request: Request[A]): Future[CharRequest[A]] = {
Future.successful(new CharRequest[A]('a', request))
}
}
// Request that contains a string and the previous request.
class StringRequest[A, PrevReqT <: Request[A]](val str: String, val prevReq: PrevReqT) extends WrappedRequest[A](prevReq)
// Enclosing class to hold the type parameter for the previous request.
// Simmilar to https://stackoverflow.com/questions/38988062/in-scala-is-it-possible-to-curry-type-parameters-of-a-def
class ChainAction[PrevReqT[X] <: Request[X]] {
// Type to ensure that the response has one type paramter in order to conform to the expectations of ActionRefiner.
type ChainedReqT[A] = StringRequest[A, PrevReqT[A]]
// Get the actual ActionRefiner for augmenting the previous request.
def chainedAction(str: String): ActionRefiner[PrevReqT, ChainedReqT] = {
new ActionRefiner[PrevReqT, ChainedReqT] {
override def executionContext: ExecutionContext = scala.concurrent.ExecutionContext.global
override def refine[A](request: PrevReqT[A]): Future[Either[Result, ChainedReqT[A]]] = {
Future.successful(Right(new ChainedReqT[A](str = str, prevReq = request)))
}
}
}
}
object ChainAction { def get[PrevReqT[X] <: Request[X]](): ChainAction[PrevReqT] = new ChainAction[PrevReqT] }
@Inject class Controller(
intAction: IntAction,
charAction: CharAction
) {
def intEndpoint(): Action[AnyContent] = {
intAction
.andThen(ChainAction.get[IntRequest].chainedAction("int value is "))
// Async should take a StringRequest => Result, but instead it takes a WrappedRequest => Result.
.async { request: StringRequest[AnyContent, IntRequest[AnyContent]] =>
Future.successful(Results.Ok(request.str + request.prevReq.num))
}
}
def charEndpoint(): Action[AnyContent] = {
charAction
.andThen(ChainAction.get[CharRequest].chainedAction("char value is "))
// Async should take a StringRequest => Result, but instead it takes a WrappedRequest => Result.
.async { request: StringRequest[AnyContent, CharRequest[AnyContent]] =>
Future.successful(Results.Ok(request.str + request.prevReq.char))
}
}
}
Не компилируется с ошибками:
[error] /home/matthew-work/temp/chain/chain/app/actions/ChainAction.scala:59:75: type mismatch;
[error] found : actions.StringRequest[play.api.mvc.AnyContent,actions.IntRequest[play.api.mvc.AnyContent]] => scala.concurrent.Future[play.api.mvc.Result]
[error] required: play.api.mvc.WrappedRequest[play.api.mvc.AnyContent] => scala.concurrent.Future[play.api.mvc.Result]
[error] .async { request: StringRequest[AnyContent, IntRequest[AnyContent]] =>
[error] ^
[error] /home/matthew-work/temp/chain/chain/app/actions/ChainAction.scala:68:76: type mismatch;
[error] found : actions.StringRequest[play.api.mvc.AnyContent,actions.CharRequest[play.api.mvc.AnyContent]] => scala.concurrent.Future[play.api.mvc.Result]
[error] required: play.api.mvc.WrappedRequest[play.api.mvc.AnyContent] => scala.concurrent.Future[play.api.mvc.Result]
[error] .async { request: StringRequest[AnyContent, CharRequest[AnyContent]] =>
[error] ^
build.sbt
:
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.12.8"
libraryDependencies += guice
plugins.sbt
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.0")
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0")
Scala версия 2.11.8, версия воспроизведения 2.8.0, sbt 1.3.8 и JVM openjdk-1.8.0.