【问题标题】:Using Reads, Writes and Formats in Play framework在 Play 框架中使用读、写和格式
【发布时间】:2014-11-24 14:44:37
【问题描述】:

我在 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 中的无效输入?上面的机制究竟是如何工作的?

【问题讨论】:

    标签: json scala validation playframework playframework-json


    【解决方案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 的实例。

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

    【讨论】:

    • 这绝对有道理。现在我想知道我昨天在浏览哪个版本时发现没有catching 的另一个定义。 :-?太糟糕了,我没有包含链接...
    • 好的,我找到了github.com/playframework/Play20/blob/master/framework/src/play/… 这是master中的版本,大概是Play 2.1的代码库。我应该看起来更好......
    猜你喜欢
    • 1970-01-01
    • 2014-02-15
    • 2013-01-20
    • 2015-06-24
    • 2015-05-16
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多