没有用于Option [String]的Json格式化程序? [英] No Json formatter for Option[String]?
问题描述
我试图封送和取消封送往返于JSON的Option [String]字段.对于我的用例,应将None值编组为"null".这是我的代码:
I am trying to marshall and un-marshall an Option[String] field to and from JSON. For my use-case, a None value should be marshaled as "null". Here is the code I have:
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)
}
}
这会导致以下编译器错误:
This results in the following compiler error:
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] ^
这些是我尝试过的一些事情:
These are some of the things I have tried:
用(__ \ "first_name").formatNullable[String]
替换(__ \ "first_name").format[Option[String]]
使编译器满意,但是测试失败(" java.util.NoSuchElementException:None.get"),输出如下(来自println(json)
)
Replacing (__ \ "first_name").format[Option[String]]
with (__ \ "first_name").formatNullable[String]
makes the compiler happy, but the test fails (""java.util.NoSuchElementException: None.get"") with the following output (from println(json)
)
{"id":1}
这可以确认formatNullable
的行为(不要呈现无值"字段).
This confirms with formatNullable
's behavior (don't render None valued fields).
接下来,我用writes
替换了格式.像这样:
Next, I replaced the format with a writes
. Like so:
object Person {
implicit lazy val personWrite = (
(__ \ "id").write[Int] and
(__ \ "first_name").write[Option[String]] and
(__ \ "last_name").write[Option[String]]
)(unlift(Person.unapply))
}
现在,编译器很高兴,测试通过了.
Now, the compiler is happy and the test passes.
但是我现在需要实现一个单独的Reads.如果可以的话,我宁愿不违反DRY原则.
But I now need to implement a separate Reads. If I could, I would rather not as it violates DRY principle.
我在做什么错,当write [Option [...]]正常工作时,为什么不格式化[Option [...]]?
What am I doing wrong and when write[Option[...]] works perfectly why not format[Option[...]]?
推荐答案
添加此代码,使其对您的PersonFormat隐式可见,将使其正常工作.
Adding this code so that it is implicit-visible from your PersonFormat will make it work.
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观察到的行为.
I think that in play it is assumed that option-valued fields should be treated optional at all, hence the behaviour you observed with formatNullable.
这篇关于没有用于Option [String]的Json格式化程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!