我在Play中有一些模特!我希望对JSON进行序列化/反序列化的应用程序。我曾经有过单独的方法,但我看到首选方法是提供Formats[T]
或Reads[T]
的隐式实例,如
import play.api.libs.json.{ JsValue, Reads }
case class Foo(bar: Int, ...)
object Foo {
implicit object FooReads extends Reads[Foo] {
def reads(json: JsValue): Foo = //whatever
}
}
现在,可能会发生模型在JSON中具有正确的字段,但它不会验证。在这种情况下,我无法反序列化 - 在使用json.as[Foo]
时使用None
或json.asOpt[Foo]
时会出现异常。
如果我发现一个未验证的字段时抛出异常,那么一切似乎都按预期工作。但我小心翼翼地试图找出我应该抛出的异常,并在JsValue
的来源中找到了这个
def asOpt[T](implicit fjs: Reads[T]): Option[T] = fjs.reads(this).fold(
valid = v => Some(v),
invalid = _ => None
).filter {
case JsUndefined(_) => false
case _ => true
}
现在,我无法理解这是如何工作的。 fjs
的隐式实例由我自己在伴随对象中提供,因此我知道fjs.reads(this)
返回Foo
或抛出异常。
fold
来自哪里?它当然不是Foo
上的方法。我猜一个人可以进行隐式转换,但它应该是从Any
到具有fold
方法的东西,因此它不会引起太大兴趣。更糟糕的是,如果fjs.reads(this)
抛出异常,就没有什么可以抓住的了!
那么,如何在
Reads[T]
的实例中处理JSON中的无效输入?上面的机制实际上如何运作?
答案 0 :(得分:1)
在Play 2.0.x中查看JsonValue.scala:
def asOpt[T](implicit fjs: Reads[T]): Option[T] = catching(classOf[RuntimeException]).opt(fjs.reads(this)).filter {
case JsUndefined(_) => false
case _ => true
}
实际上代码正在使用scala.util.control.Exception.catching[T](exceptions: Class[_]*): Catch[T],它返回Catch[T]
。然后它会调用opt(...)。如果抛出异常,则它将返回None而不是T
的实例。
因此,当您收到反序列化错误时,可以安全地抛出异常。