Azik
Azik

Reputation: 179

Update all values from any Json

I've got some json and I have to encrypt all the values. Below is a json, all the values of which should be updated:

json = Json.parse("""{
    "key1" : 1.5,
    "key2" : [
        {"key211": 1, "key212": "value212"},
        {"key221": 2, "key222": "value222"}
    ]
    "key3" : {
        "key31" : true,
        "key32" : "value32"
    },
    "key4" : 17
}"""

After encrypting and updating all the values, it should look like this:

val json = Json.parse("""{
    "key1" : "uhKhbofQtL",
    "key2" : [
        {"key211": "FxnbGGZFMW", "key212": "VsdfdGfg"},
        {"key221": "sdffFdd", "key222": "Fsdfsfds"}
    ]
    "key3" : {
        "key31" : "Fsdfasdf",
        "key32" : "Vsdfsdfsdfs"
    },
    "key4" : "sfsdfFSdfs"
}"""

How can I do it?

Upvotes: 0

Views: 127

Answers (2)

Azik
Azik

Reputation: 179

I've solved this problem and solution is below

  implicit val readsMap: Reads[Map[String, Any]] = Reads[Map[String, Any]](m => Reads.mapReads[Any](metaValueReader).reads(m))
  implicit val writesMap: Writes[Map[String, Any]] = Writes[Map[String, Any]](m => Writes.mapWrites[Any](metaValueWriter).writes(m))

  def metaValueReader(jsValue: JsValue): JsResult[Any] = jsValue match {
    case JsObject(m) => JsSuccess(m.map { case (k, v) => k -> metaValueReader(v) })
    case JsArray(arr) => JsSuccess(arr.map(metaValueReader))
    case JsBoolean(b) => JsSuccess(b).map(encryptValue)
    case JsNumber(n) => JsSuccess(n).map(encryptValue)
    case JsString(s) => JsSuccess(s).map(encryptValue)
    case JsNull => JsSuccess("").map(encryptValue)
    case badValue => JsError(s"$badValue is not a valid value")
  }

  def metaValueWriter(value: Any): JsValue = value match {
    case jsRes: JsSuccess[Any] => metaValueWriter(jsRes.get)
    case m: Map[String, Any] => JsObject(m.map { case (k, v) => k -> metaValueWriter(v) })
    case arr: Seq[Any] => JsArray(arr.map(metaValueWriter))
    case s: String => JsString(s)
  }

How can I improve this code?

Upvotes: 0

Dima
Dima

Reputation: 40500

Parse it as a Map, then traverse the map and encrypt:

 def encrypt(data: Any, enc: Any => String): Any = data match { 
   case v: Map[String, Any] => v.map { case (k,v) => k -> encrypt(v, enc) }
   case v: List[Any] => v.map(encrypt(_, enc))
   case v => enc(v)
}

Upvotes: 3

Related Questions