我试图实施basically the same thing that is discussed here,但在我的具体情况下,它无效。
目前我有一个验证来自我们服务器的JSON响应的函数。问题是,它将JSON类型硬编码到方法中:
def fakeRequest[A: Writes](target: () => Call, requestObject: A): Any = {
route(FakeRequest(target()).withJsonBody(Json.toJson(requestObject))) match {
// ... stuff happens
Json.parse(contentAsString(response)).validate[GPInviteResponse]
^
请注意硬编码的 GPInviteResponse 类型。
因此,为了使它成为一个完全通用且可重用的方法,传入正在验证的类型会很棒。
我试过了:
def fakeRequest[A: Writes, B](target: () => Call, requestObject: A, responseType: B): Any = {
route(FakeRequest(target()).withJsonBody(Json.toJson(requestObject))) match {
// ... stuff happens
Json.parse(contentAsString(response)).validate[B]
^
这几乎可行,但我得到No Json deserializer found for type B.
有道理,所以我改为:
def fakeRequest[A: Writes, B: Reads](target: () => Call, requestObject: A, responseType: B): Any = {
但是,现在我得到No Json deserializer found for type controllers.GPInviteResponse.type.
所以问题是:是否可以传递这样的类型(或者还有其他魔法可以使它工作)?
为该类型定义了一个反序列化程序...我已经重读了六次,以确保没有拼写错误:
case class GPInviteResponse(inviteSent: Boolean, URL: Option[String], error: Option[GPRequestError] = None) {
def this(error: GPRequestError) = this(false, None, Option(error))
}
object GPInviteResponse {
implicit val readsInviteResponse = Json.reads[GPInviteResponse]
implicit val writesInviteResponse = Json.writes[GPInviteResponse]
}
修改
下面是一个简化的测试用例,用于演示此问题。目前,这不会编译(错误如下所示)。我想我理解为什么它不能工作(模糊地),但我不知道解决方案。关于它为什么不能工作的理论:虽然提供的类型GPInviteRequest
确实有一个隐式的Reads / Writes方法,但Scala无法建立实例B
实际上是{{1}的连接所以它得出的结论是GPInviteRequest
没有读/写。
B
上述测试结果如下:
[错误] /Users/zbeckman/Projects/Glimpulse/Server-2/project/glimpulse-server/test/application/TestInviteServices.scala:46: 没有找到类型B的Json序列化程序。尝试实现隐式 此类型的写入或格式。 [错误] val json = Json.toJson(i).toString [错误] ^ [错误] /Users/zbeckman/Projects/Glimpulse/Server-2/project/glimpulse-server/test/application/TestInviteServices.scala:133: 找不到类型controllers.GPInviteResponse.type的Json反序列化器。 尝试为此类型实现隐式读取或格式。 [错误] fakeRequest(controllers.routes.GPInviteService.invite,i, GPInviteResponse)匹配{[error] ^
答案 0 :(得分:2)
您的错误消息:
找不到类型B的Json序列化程序。尝试为此类型实现隐式写入或格式。
在此函数中,toJson
方法如何知道如何序列化类型B?
def tryToValidate[B: Reads, Writes](i: B) = {
val json = Json.toJson(i).toString
Json.parse(json).validate[B].isSuccess must beTrue
}
你没有将编写器/读取器引入范围,编译器不知道在哪里查找,这就是它告诉你实现它的原因。这是一个快速的解决方案
case class GPInviteResponse(inviteSent: Boolean)
object GPInviteResponse {
implicit val format = Json.format[GPInviteResponse]
}
def tryToValidate[B](i: B)(implicit format: Format[B]) = {
val json = Json.toJson(i).toString
Json.parse(json).validate[B]
}
注意:使用format
方法相当于定义reads
和writes
。
现在,范围内有B
的隐式格式化程序,因此编译器知道在哪里找到它并将其注入validate
方法,该方法隐含地采用reader
:
// From play.api.libs.json
def validate[T](implicit rds: Reads[T]): JsResult[T] = rds.reads(this)
修改强>
您可以向函数添加类型参数,然后在validate[T]
方法中引用它们,如下所示:
// Define another case class to use in the example
case class Foo(bar: String)
object Foo {
implicit val format = Json.format[Foo]
}
def tryToValidate[B, C](implicit f1: Format[B], f2: Format[C]) = {
val j1 = """{"inviteSent":true}"""
val j2 = """{"bar":"foobar"}""" //
Json.parse(j1).validate[B]
Json.parse(j2).validate[C]
}
// Example call
tryToValidate[GPInviteResponse, Foo]
答案 1 :(得分:1)
以这种方式尝试:
def tryToValidate[B](i: B)(implicit format : Format[B]) = {
val json = Json.toJson(i).toString
Json.parse(json).validate[B].isSuccess must beTrue
}