1

我在 Play 中有一些模型!我想从 JSON 序列化/反序列化的应用程序。我曾经有单独的方法,但我已经看到首选的方法是给出Formats[T]or的隐式实例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)要么返回 aFoo要么抛出异常。

这是fold从哪里来的?它当然不是一种方法Foo。我想一个人可能有一个隐式转换,但它应该是从Any某种fold方法到某物,所以它不会引起太大兴趣。更糟糕的是,如果fjs.reads(this)抛出异常,则没有任何东西可以捕获它!

那么,应该如何处理 JSON 中的无效输入Reads[T]?上面的机制实际上是如何工作的?

4

1 回答 1

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. catch[T](exceptions: Class[_]*): Catch[T],它返回一个Catch[T]. 然后它调用 opt(...) 。如果抛出异常,那么它将返回 None 而不是T.

因此,当您在反序列化时遇到错误时,您可以安全地抛出异常。

于 2012-10-06T12:39:52.127 回答