Option [String]没有Json格式化程序?

Bab*_*nam 9 json scala play-json

我正在尝试对JSON中的Option [String]字段进行编组和取消编组.对于我的用例,None值应该被封送为"null".这是我的代码:

import org.scalatest.{FlatSpec, Matchers}

import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._


case class Person(
  id: Int,
  firstName: Option[String],
  lastName: Option[String]
)

object Person {
  implicit lazy val personFormat = (
    (__ \ "id").format[Int] and
    (__ \ "first_name").format[Option[String]] and
    (__ \ "last_name").format[Option[String]]
  )(Person.apply, unlift(Person.unapply))
}

class PersonSpec extends FlatSpec with Matchers {
  "When Person instance is marshaled None fields " should
    "be serialized as \"null\" values" in {
    val person = Person(1, None, None)
    import Person._
    val json = Json.toJson(person)
    println(json)
    (json \ "id").as[Int] should be (1)
    (json \ "first_name").get should be (JsNull)
    (json \ "last_name").get should be (JsNull)
  }
}
Run Code Online (Sandbox Code Playgroud)

这会导致以下编译器错误:

PersonSpec.scala:19: No Json formatter found for type Option[String]. Try to implement an implicit Format for this type.
[error]     (__ \ "first_name").format[Option[String]] and
[error]                               ^
Run Code Online (Sandbox Code Playgroud)

这些是我尝试过的一些事情:

更换(__ \ "first_name").format[Option[String]](__ \ "first_name").formatNullable[String]使编译器高兴,但测试失败("" java.util.NoSuchElementException:None.get"")与下列输出(从println(json))

{"id":1}
Run Code Online (Sandbox Code Playgroud)

这确认了formatNullable行为(不渲染无值字段).

接下来,我用a替换了格式writes.像这样:

object Person {
  implicit lazy val personWrite = (
    (__ \ "id").write[Int] and
    (__ \ "first_name").write[Option[String]] and
    (__ \ "last_name").write[Option[String]]
  )(unlift(Person.unapply))
}
Run Code Online (Sandbox Code Playgroud)

现在,编译器很高兴并且测试通过了.

但我现在需要实现一个单独的Reads.如果可以的话,我宁愿不要因为它违反DRY原则.

我做错了什么,当写[Option [...]]完全有效时为什么不格式化[Option [...]]?

Tom*_*rek 13

添加此代码以使其从PersonFormat隐式可见将使其工作.

implicit def optionFormat[T: Format]: Format[Option[T]] = new Format[Option[T]]{
    override def reads(json: JsValue): JsResult[Option[T]] = json.validateOpt[T]

    override def writes(o: Option[T]): JsValue = o match {
      case Some(t) ? implicitly[Writes[T]].writes(t)
      case None ? JsNull
    }
  }
Run Code Online (Sandbox Code Playgroud)

我认为在游戏中假设选项值字段应该被视为可选的,因此您使用formatNullable观察到的行为.


小智 6

您可以使用:

(__ \ "first_name").formatNullable[String]
Run Code Online (Sandbox Code Playgroud)