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)Foo

これはどこ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.ching[T](exceptions: Class[_]*): Catch[T]を使用しており、これはCatch[T]. 次に、 opt(...) を呼び出します。例外がスローされると、 のインスタンスではなく None が返されますT

したがって、逆シリアル化でエラーが発生した場合は、安全に例外をスローできます。

于 2012-10-06T12:39:52.127 に答える