为什么不是序列化的Option [String]类型的成员?

时间:2017-02-26 13:45:40

标签: json scala serialization optional play-json

我有一个虚拟课程Foo,有三个成员:

import play.api.libs.json.Json

case class Foo(id: String, fooType: FooType, nextId: Option[String])

object Foo {
  implicit val fooReads = Json.reads[Foo]
  implicit val fooFormat = Json.format[Foo]
}

其中FooType定义为

import play.api.libs.json.Json

case class FooType(a: String, b: String)

object FooType {
  implicit val fooTypeReads = Json.reads[FooType]
  implicit val fooTypeFormat = Json.format[FooType]
}

在序列化Foo对象时,我发现了一些有趣的行为。如果我将Foo序列化为JSON,解析JSONified Foo,我发现所有成员都被正确解析:

val id = "id"
val fooType = FooType("a", "b")
val nextId = None

val foo = Foo(id, fooType, nextId)
val jsonFoo = Json.toJson(foo)
val parsedFoo = Json.parse(jsonFoo.toString).as[Foo]

assert(parsedFoo == foo)
assert(parsedFoo.id == id)
assert(parsedFoo.fooType == fooType)
assert(parsedFoo.nextId.isEmpty)

这很好,因为这是我的期望。

但是,在我的下一个测试中,我发现nextId字段可以序列化:

val id = "id"
val fooType = FooType("a", "b")
val nextId = None

val foo = Foo(id, fooType, nextId)
val jsonFoo = Json.toJson(foo)

assert((jsonFoo \ "id").as[String] == id)
assert((jsonFoo \ "fooType").as[FooType] == fooType)
assert((jsonFoo \ "nextId").as[Option[String]].isEmpty)

此操作失败,并显示以下错误:

Error:(38, 35) No Json deserializer found for type Option[String]. Try to implement an implicit Reads or Format for this type.
    assert((jsonFoo \ "nextId").as[Option[String]].isEmpty)

Error:(38, 35) not enough arguments for method as: (implicit fjs: play.api.libs.json.Reads[Option[String]])Option[String].
Unspecified value parameter fjs.
    assert((jsonFoo \ "nextId").as[Option[String]].isEmpty)

同样,我发现当我打印Json.toJson(foo)转储的JSON对象时,JSON对象中缺少nextId字段:

println(Json.prettyPrint(jsonFoo))

{
  "id" : "id",
  "fooType" : {
    "a" : "a",
    "b" : "b"
  }
}

但是,我可以使用nextId解析toOption字段;即,

assert((jsonFoo \ "nextId").toOption.isEmpty)

如果其中一个成员本身不可反序列化,如何从JSON中正确解析我的对象?

1 个答案:

答案 0 :(得分:2)

nextId字段是可序列化的,否则,您根本无法将Foo写入JSON。

jsonFoo: play.api.libs.json.JsValue = {"id":"id","fooType":{"a":"a","b":"b"}}

您遇到的问题是Reads没有Option[A]。选项由Play JSON专门处理。使用JSON组合器时,我们使用readNullable[A]writeNullable[A]代替read[Option[A]]write[Option[A]]。同样,当使用方法从JsValue中提取单个字段时,调用as将无效,因为它需要为您提供的类型隐式Reads[A](在本例中为{{1} },但不存在)。

相反,您需要使用Reads[Option[String]],这将正确处理下面的asOpt

Option

scala> (jsonFoo \ "nextId").asOpt[String] res1: Option[String] = None 未出现在打印的JSON中,因为您要序列化的值为nextId。这是预期会发生的事情。由于该值是可选的,因此它从JSON中省略(在JavaScript中它只是None)。如果它有一个值,它将出现:

undefined

如果使用Play JSON无法序列化某些内容,则无法编译。

相关问题