如何通过 Scala 中的参数化类型获取隐式 val/def?
How to obtain implicit val/def via parameterized types in scala?
我正在使用 Playframework 2.5 并尝试制作一个所有 Json request/response 控制器方法调用的方法,以避免在每个控制器方法内部编写 implicit val foo = Json.writes[Bar] or reads[Bar]
以及处理基本验证和 return 错误代码。
将由每个控制器继承的BaseController
class BaseController @Inject()(implicit exec: ExecutionContext) extends Controller {
def handleJson[T <: RequestModel,U <: ResponseModel](request: Request[JsValue])(cb: (T) => Future[U]):Future[Result] = {
implicit val convertReq = Json.reads[T]
implicit val convertRes = Json.writes[U]
val reqOpt = request.body.asOpt[T]
reqOpt match {
case Some(data) =>
cb(data).map{x => Ok(Json.toJson(x))}
case None =>
Future.successful(Ok(Json.obj("foo" -> "bar")))
}
}
}
控制器
def send = Action.async(parse.json) { req =>
handleJson[RequestCaseClass,ResponseCaseClass](req)( (x) =>
injectedClass.foo(x.bar).map{ case (success: Boolean,mes: String) =>
if(success) SendRes(SomethingForSuccess)
else SendRes(SomethingForError)
}
)
}
上面的代码无法编译,因为 handleJson
的 implicit val convertReq = Json.reads[T]
和 implicit val convertRes = Json.writes[U]
表示
No Json deserializer found for type T. Try to implement an implicit
Reads or Format for this type.
我已经尝试制作 case class 的伴随对象并将隐式放入其中,尽管这不能解决任何问题。
我的问题是,如何使用参数化类型的隐式值?
提前致谢。
您可以在调用 handleJson
之前初始化 implicit
变量,并将 convertReq
和 convertRes
设置为 handleJson
:
的隐式方法参数
def send = Action.async(parse.json) { req =>
implicit val convertReq = Json.reads[RequestCaseClass]
implicit val convertRes = Json.writes[ResponseCaseClass]
handleJson[RequestCaseClass,ResponseCaseClass](req)( (x) =>
injectedClass.foo(x.bar).map{ case (success: Boolean,mes: String) =>
if(success) SendRes(SomethingForSuccess)
else SendRes(SomethingForError)
}
)
}
def handleJson[T <: RequestModel,U <: ResponseModel](request: Request[JsValue])(cb: (T) => Future[U])(implicit convertReq: Reads, convertRes: Writes):Future[Result] = {
val reqOpt = request.body.asOpt[T]
reqOpt match {
case Some(data) =>
cb(data).map{x => Ok(Json.toJson(x))}
case None =>
Future(Ok(Json.obj("foo" -> "bar")))
}
}
我建议这样做
class Application @Inject()(implicit exec: ExecutionContext) extends Controller {
def handleJson[A : Reads, B : Writes](request: Request[JsValue])(cb: A => Future[B]): Future[Result] = {
val reqOpt = request.body.asOpt[A]
reqOpt match {
case Some(data) =>
cb(data).map { x => Ok(Json.toJson(x)) }
case None =>
Future.successful(Ok(Json.obj("foo" -> "bar")))
}
}
def index = Action.async(parse.json) { req =>
handleJson[MyReq, MyResp](req)(x => Future.successful(MyResp((x.i to x.i + 4).toList)))
}
}
您不必用任何特征来约束您的模型,只要隐含的 Reads
和 Writes
存在即可。
为确保这一点,最好在 class 的伴随对象中定义 Reads
和 Writes
。当您导入模型时,您会将它们带到隐式范围 classes.
object MyReq {
implicit val myReqReads: Reads[MyReq] = Json.reads[MyReq]
}
case class MyReq(i: Int)
object MyResp {
implicit val myRespWrites: Writes[MyResp] = Json.writes[MyResp]
}
case class MyResp(l: List[Int])
我正在使用 Playframework 2.5 并尝试制作一个所有 Json request/response 控制器方法调用的方法,以避免在每个控制器方法内部编写 implicit val foo = Json.writes[Bar] or reads[Bar]
以及处理基本验证和 return 错误代码。
将由每个控制器继承的BaseController
class BaseController @Inject()(implicit exec: ExecutionContext) extends Controller {
def handleJson[T <: RequestModel,U <: ResponseModel](request: Request[JsValue])(cb: (T) => Future[U]):Future[Result] = {
implicit val convertReq = Json.reads[T]
implicit val convertRes = Json.writes[U]
val reqOpt = request.body.asOpt[T]
reqOpt match {
case Some(data) =>
cb(data).map{x => Ok(Json.toJson(x))}
case None =>
Future.successful(Ok(Json.obj("foo" -> "bar")))
}
}
}
控制器
def send = Action.async(parse.json) { req =>
handleJson[RequestCaseClass,ResponseCaseClass](req)( (x) =>
injectedClass.foo(x.bar).map{ case (success: Boolean,mes: String) =>
if(success) SendRes(SomethingForSuccess)
else SendRes(SomethingForError)
}
)
}
上面的代码无法编译,因为 handleJson
的 implicit val convertReq = Json.reads[T]
和 implicit val convertRes = Json.writes[U]
表示
No Json deserializer found for type T. Try to implement an implicit Reads or Format for this type.
我已经尝试制作 case class 的伴随对象并将隐式放入其中,尽管这不能解决任何问题。
我的问题是,如何使用参数化类型的隐式值?
提前致谢。
您可以在调用 handleJson
之前初始化 implicit
变量,并将 convertReq
和 convertRes
设置为 handleJson
:
def send = Action.async(parse.json) { req =>
implicit val convertReq = Json.reads[RequestCaseClass]
implicit val convertRes = Json.writes[ResponseCaseClass]
handleJson[RequestCaseClass,ResponseCaseClass](req)( (x) =>
injectedClass.foo(x.bar).map{ case (success: Boolean,mes: String) =>
if(success) SendRes(SomethingForSuccess)
else SendRes(SomethingForError)
}
)
}
def handleJson[T <: RequestModel,U <: ResponseModel](request: Request[JsValue])(cb: (T) => Future[U])(implicit convertReq: Reads, convertRes: Writes):Future[Result] = {
val reqOpt = request.body.asOpt[T]
reqOpt match {
case Some(data) =>
cb(data).map{x => Ok(Json.toJson(x))}
case None =>
Future(Ok(Json.obj("foo" -> "bar")))
}
}
我建议这样做
class Application @Inject()(implicit exec: ExecutionContext) extends Controller {
def handleJson[A : Reads, B : Writes](request: Request[JsValue])(cb: A => Future[B]): Future[Result] = {
val reqOpt = request.body.asOpt[A]
reqOpt match {
case Some(data) =>
cb(data).map { x => Ok(Json.toJson(x)) }
case None =>
Future.successful(Ok(Json.obj("foo" -> "bar")))
}
}
def index = Action.async(parse.json) { req =>
handleJson[MyReq, MyResp](req)(x => Future.successful(MyResp((x.i to x.i + 4).toList)))
}
}
您不必用任何特征来约束您的模型,只要隐含的 Reads
和 Writes
存在即可。
为确保这一点,最好在 class 的伴随对象中定义 Reads
和 Writes
。当您导入模型时,您会将它们带到隐式范围 classes.
object MyReq {
implicit val myReqReads: Reads[MyReq] = Json.reads[MyReq]
}
case class MyReq(i: Int)
object MyResp {
implicit val myRespWrites: Writes[MyResp] = Json.writes[MyResp]
}
case class MyResp(l: List[Int])