我正在使用play框架版本2.2.3的json库。我有以下json对象:
{
"myData":
[
{
"A": "some text",
"B": [10, 20, 30]
},
{
"A": "some other text",
"B": [15, 25, 35]
},
...
]
}
我想将此json对象反序列化为Vector[Map[String, Vector[Int]]]
。所以结果应该是:
Vector(Map("some text" -> Vector(10, 20, 30)), Map("some other text" -> Vector(15, 25, 35)))
在我尝试实现这一目标的过程中,我能够编写一个Reads[Map[String, Vector[Int]]]
来为单个条目执行此操作。
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val singleEntryReads: Reads[Map[String, Vector[Int]]] = {
(__).read(
(__ \ "A").read[String] and
(__ \ "B").read[Vector[Int]] tupled) map { keyAndValue =>
val (a, b) = keyAndValue
Map(a -> b)
}
}
因此转换适用于单个条目:
scala> (myJsonObject \ "myData")(0).validate[Map[String, Vector[Int]]]
res: play.api.libs.json.JsResult[Map[String, Vector[Int]]] = JsSuccess(Map(some text -> Vector(10, 20, 30)))
但我怎么能写一个Reads[Vector[Map[String, Vector[Int]]]]
?我最好的想法是将其与this older question给出的答案类似:
implicit val allEntriesReads: Reads[Seq[Map[String, Vector[Int]]]] = Reads.seq(singleEntryReads)
我试着像这样使用它:
scala> (myJsonObject \ "myData").validate[Seq[Map[String, Vector[Int]]]]"
res2: play.api.libs.json.JsResult[Seq[Map[String, Vector[Int]]]] = JsError(List(((147)/B,List(ValidationError(error.path.missing,WrappedArray()))), ((148)/B,List(ValidationError(error.path.missing,WrappedArray())))))
但这不起作用并给我一个JsError()
。我如何实现第二个Reads
以使其以这种方式工作?
答案 0 :(得分:2)
你不需要。玩!附带一个隐含的(在Reads
伴随对象中定义)已经做了你想做的事情:
implicit def traversableReads[F[_], A](implicit bf: CanBuildFrom[F[_], A, F[A]], ra: Reads[A]): Reads[F[A]]
如果序列类型有隐式Reads[A]
和适当的CanBuildFrom
(标准库集合类型已经存在,例如Vector
),那么这个隐式将充当隐式Reads[F[A]]
其中F
是集合类型。
Scala允许您定义一个本身采用隐式参数的implicit def
,它将作为其返回类型的隐式值。使用implicit def
时,Scala将在呼叫站点搜索隐式参数。所以:
.validate[Seq[Map[String, Vector[Int]]]]
变为:
.validate[Seq[Map[String, Vector[Int]]]](traversableReads)
然后成为:
.validate[Seq[Map[String, Vector[Int]]]](traversableReads(singleEntryReads, Seq.canBuildFrom)