[英]play-json: how to get value of “dynamic” key using Reads[T]?
我有一个Seq
的JsValue
元素。 每个元素代表具有两个字段的以下JSON结构:
{
"name": "xy"
"key ∈ {A,B,C}": ["// some values in an array"]
}
这意味着我知道第一个字段的键(总是“ name”),但不知道数组的键,因为它是“ dynamic”的。 但是: 可能的键是已知的,可以是“ A”,“ B”或“ C”。
我想做的是将每个这些JsValue
对象映射到case类:
case class Element(name: String, values: Seq[String])
如您所见,动态密钥的名称甚至都不重要。 我只想获取与其关联的数组。
但是:如果键不同,如何使用Reads[T]
获取数组?
implicit val reads: Reads[Element] = (
(__ \ "name").read[String] and
(__ \ "???").read[Seq[String]]
)(Element.apply _)
还是必须“手动”完成,如果是,怎么做?
您可以使用orElse
方法
case class Element(name: String, values: Seq[String])
object Element {
implicit val reads: Reads[Element] = (
(__ \ "name").read[String] and
(__ \ "a").read[Seq[String]]
.orElse((__ \ "b").read[Seq[String]])
.orElse((__ \ "c").read[Seq[String]])
)(Element.apply _)
}
如其他答案所述, orElse
可以在这里工作,但是如果您希望获得更大的灵活性,则可以始终编写类似返回“ Reads
的方法来查找满足某些谓词的键的方法:
import play.api.libs.json._
def findByKey[A: Reads](p: String => Boolean): Reads[A] = Reads[A] {
case JsObject(fields) => fields.find(kv => p(kv._1)).map(
_._2.validate[A]
).getOrElse(JsError("No valid field key"))
case _ => JsError("Not an object")
}
接着:
import play.api.libs.functional.syntax._
case class Element(name: String, values: Seq[String])
object Element {
implicit val reads: Reads[Element] = (
(__ \ "name").read[String] and findByKey[Seq[String]](Set("A", "B", "C"))
)(Element.apply _)
}
最后:
scala> Json.parse("""{ "name": "foo", "A": ["bar", "baz"] }""").asOpt[Element]
res0: Option[Element] = Some(Element(foo,List(bar, baz)))
scala> Json.parse("""{ "name": "foo", "A": [1, 2] }""").asOpt[Element]
res1: Option[Element] = None
您选择哪种方法取决于您的口味,并且可能部分取决于更通用的findByKey
在其他情况下是否对您有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.