Timothy Wang
Timothy Wang

Reputation: 41

Play framework JSON transformers, how to work with recursive paths (jsPath)?

Suppose I have a JSON like this:

{
  "name" : "Watership Down",
  "location" : {
    "lat" : 51.235685,
    "long" : -1.309197
  },
  "residents" : [ {
    "name" : "Fiver",
    "age" : 4,
    "role" : null
  }, {
    "name" : "Bigwig",
    "age" : 6,
    "role" : "Owsla"
  } ]
}

If I do

val transformer1 = (__ \ 'name).json.update(of[JsValue].map(a => JsString("x")))

to change the name field to "x" it works fine.

But if I want to recursively change all the names to "x", I thought I could just use the recursive jsPath, like this:

val transformerRecursive = (__ \\ 'name).json.update(of[JsValue].map(a => JsString("x")))

But when I try it, I get this error:

scala> jsobject.transform(transformerRecursive) res1: play.api.libs.json.JsResult[play.api.libs.json.JsObject] = JsError(List((//name,List(ValidationError(List(error.path.result.multiple),WrappedArray())))))

How should I use recursive path with JSON Transformer in playframework?

Upvotes: 4

Views: 1141

Answers (2)

Peter Perháč
Peter Perháč

Reputation: 20792

Thanks to @andrey.ladniy I managed to solve my problem where i wanted to empty out a nested JsArray. Here's a sample of how that can be done, just for anyone who might find that of any assistance:

import play.api.libs.json._

case class D(yay: String, nay: String)
case class C(ds: Seq[D], baz: Boolean)
case class B(cs: Seq[C], bar: Int)
case class A(b: B, foo: String)

implicit val formatD: OFormat[D] = Json.format
implicit val formatC: OFormat[C] = Json.format
implicit val formatB: OFormat[B] = Json.format
implicit val formatA: OFormat[A] = Json.format

val foo = A(
  B(Seq(C(Seq(D("foo", "bar")), true), C(Seq(D("oof", "rab")), false)), 42),
  "test"
)

val dsIgnoringReads =
  (__ \ "b" \ "cs").json.update(Reads.seq((__ \ "ds").json.update(Reads.pure(JsArray()))).map(JsArray))

dsIgnoringReads.reads(Json.toJson(foo)).get

This produces

res0: play.api.libs.json.JsObject = 
  {"b":{"cs":[{"ds":[],"baz":true},{"ds":[],"baz":false}],"bar":42},"foo":"test"}

Upvotes: 2

andrey.ladniy
andrey.ladniy

Reputation: 1674

As @irundaia said, you need iterate over array and update each value (use Reads.list for this):

val t = (__ \ "residents").json.update(
  Reads.list(
    (__ \ "name").json.update(
      Reads.pure(JsString("x"))
    )
  ).map(JsArray)
)

scala> res1: play.api.libs.json.JsResult[play.api.libs.json.JsObject] = JsSuccess({"name":"Watership Down","location":{"lat":51.235685,"long":-1.309197},"residents":[{"name":"x","age":4,"role":null},{"name":"x","age":6,"role":"Owsla"}]},/residents)

Upvotes: 3

Related Questions