对于像这样的案例类,我希望有一个类似Reads[Patch[T]]
的读取
sealed trait Patch[+T]
case class Update[+T](value: T) extends Patch[T]
case object Delete extends Patch[Nothing]
case object Ignore extends Patch[Nothing]
缺少的json值读取到Ignore
,空的json值读取到Delete
,有效的当前值读取到Patch
。
是否可以像这样实施Reads
?
Json4s有一个JNothing
类型,玩json有没有办法实现相同的功能(我知道JsValue下没有任何类型的东西)?
编辑:有关如何使用此内容的背景信息,请参阅json merge patch rfc。
答案 0 :(得分:0)
如果我们使用这个对象系列,暂且不讨论Patch[Nothing]
是否是一个好主意:
sealed trait Patch[+T]
case class Update[+T](value: T) extends Patch[T]
case object Delete extends Patch[Nothing]
case object Ignore extends Patch[Nothing]
我们可以通过实现包装类来获得所需的行为:
case class PatchContainer[T](patch: Patch[T])
我们必须这样做,否则我们会失去null
值与完全缺失patch
之间的重要区别。
现在,只要我们提供合适的Reads
(例如PatchContainer[T]
或Reads[T]
等),我们就可以为String
写Int
:
class PatchContainerJson[T](implicit val rdst:Reads[T]) {
implicit val patchContainerReads = new Reads[PatchContainer[T]] {
override def reads(json: JsValue): JsResult[PatchContainer[T]] = {
json.validate[JsObject].map { obj =>
(obj \ "patch").asOpt[T].fold[PatchContainer[T]] {
if (obj.keys.contains("patch")) {
PatchContainer(Delete)
} else {
PatchContainer(Ignore)
}
} { v =>
PatchContainer(Update(v))
}
}
}
}
}
这里的“技巧”是检测对象中是否有patch
个密钥(使用keys.contains
),以获得所需的Delete
vs Ignore
行为。< / p>
用法示例:
scala> import play.api.libs.json._
scala> val json = Json.parse(""" { "patch": 42 } """ )
json: play.api.libs.json.JsValue = {"patch":42}
scala> val pcti = new PatchContainerJson[Int]()
scala> import pcti._
scala> val result = json.validate[PatchContainer[Int]]
result: play.api.libs.json.JsResult[models.PatchContainer[Int]] = JsSuccess(PatchContainer(Update(42)),)
scala> result.get.patch
res0: models.Patch[Int] = Update(42)
和
...
scala> val ignoredJson = Json.parse(""" { } """)
scala> ignoredJson.validate[PatchContainer[Int]]
res1: play.api.libs.json.JsResult[models.PatchContainer[Int]] = JsSuccess(PatchContainer(Ignore),)
和
scala> val deleteJson = Json.parse(""" { "patch": null } """)
scala> deleteJson.validate[PatchContainer[Int]]
res2: play.api.libs.json.JsResult[models.PatchContainer[Int]] = JsSuccess(PatchContainer(Delete),)