在Play框架中使用Reads,Writes和Formats

时间:2012-10-05 16:25:35

标签: json scala validation playframework playframework-json

我在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]时使用Nonejson.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中的无效输入?上面的机制实际上如何运作?

1 个答案:

答案 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的实例。

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