选项 [String] 没有 Json 格式化程序?
No Json formatter for Option[String]?
我正在尝试编组和取消编组一个 Option[String] 字段和 JSON。对于我的用例,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)
}
}
这会导致以下编译器错误:
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] ^
这些是我尝试过的一些方法:
用 (__ \ "first_name").formatNullable[String]
替换 (__ \ "first_name").format[Option[String]]
使编译器满意,但测试失败(“"java.util.NoSuchElementException: None.get"”),输出如下(来自 println(json)
)
{"id":1}
这证实了 formatNullable
的行为(不呈现 None 值字段)。
接下来,我将格式替换为 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))
}
现在,编译器很高兴并且测试通过了。
但我现在需要实现一个单独的读取。如果可以,我宁愿不这样做,因为它违反了 DRY 原则。
我哪里做错了,write[Option[...]] 完美运行时为什么不格式化 [Option[...]]?
添加此代码以使其从您的 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
}
}
我认为在游戏中假设选项值字段应该被视为可选的,因此您使用 formatNullable 观察到的行为。
您可以使用:
(__ \ "first_name").formatNullable[String]
我正在尝试编组和取消编组一个 Option[String] 字段和 JSON。对于我的用例,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)
}
}
这会导致以下编译器错误:
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] ^
这些是我尝试过的一些方法:
用 (__ \ "first_name").formatNullable[String]
替换 (__ \ "first_name").format[Option[String]]
使编译器满意,但测试失败(“"java.util.NoSuchElementException: None.get"”),输出如下(来自 println(json)
)
{"id":1}
这证实了 formatNullable
的行为(不呈现 None 值字段)。
接下来,我将格式替换为 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))
}
现在,编译器很高兴并且测试通过了。
但我现在需要实现一个单独的读取。如果可以,我宁愿不这样做,因为它违反了 DRY 原则。
我哪里做错了,write[Option[...]] 完美运行时为什么不格式化 [Option[...]]?
添加此代码以使其从您的 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
}
}
我认为在游戏中假设选项值字段应该被视为可选的,因此您使用 formatNullable 观察到的行为。
您可以使用:
(__ \ "first_name").formatNullable[String]