我正在使用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才能使它以这种方式工作?
发布于 2014-06-12 19:43:09
你不需要这么做。玩!它附带了一个隐式(在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]]将充当隐式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)https://stackoverflow.com/questions/24191640
复制相似问题