How to replace a JSON value in Play
Asked Answered
K

5

20

How do I replace a value in a JSON value in Play?
Code to illustrate:

def newReport() = Action(parse.json) { request =>
    var json = request.body
    if((json \ "customerId").as[Int] == -1){
      // replace customerId after some logic to find the new value
    }
    json.validate[Report](Reports.readsWithoutUser).map {
      case _: Report =>
Kaylyn answered 1/2, 2013 at 15:5 Comment(3)
you don't manipulate json strings. down that road lies madness. you convert the json string to a native data structure, manipulate the structure, then re-encode to json.Inhabiter
Like MarcB, or use Json Coast2Coast features mandubian.com/2012/10/29/…Corrosion
If my answer was helpful for you, please select it as the accepted answer.Gargantuan
G
37

According to the Play Documentation, JsObjects have a method ++ that will merge two JsObjects. So, when you have your new integer value, you simply need:

val updatedJson = json.as[JsObject] ++ Json.obj("customerId" -> newValue)

As of Play 2.4.x you can use +:

val updatedJson = json.as[JsObject] + ("customerId" -> newValue)

(NOTE: the + method was added already in 2.1.x but adds a duplicate field to the object instead of replacing the existing value in versions prior to 2.4.x)

Gargantuan answered 5/8, 2013 at 23:36 Comment(1)
Json Transformers (coast to coast) are currently the standardHollands
D
4

One approach is, as Marc B says, convert the JSON to something like a case class, manipulate that, and then create a new JSON.

However you can also use JSON 'transformers'. Effectively what you do is build a Reads[SomeThing] object. This object is passed to the transform method which you call on your JSON object. It will change the JSON object and return a Success(result) or Failure(error) where result is the new modified JSON. Here's a (comparatively)very simple example:

using json of format: {key -> value}

def jsonXForm(value: String) = (__ \ "customerId").json.update(
  (__ \ "customerId").json.put(JsString(value))
)
json.transform(jsonXForm(yourNewValue)) match {...}`

There is a decent guide here

Daiseydaisi answered 25/2, 2016 at 22:1 Comment(0)
K
2

Something along the lines of:

val updatedJson = if((request.body \ "customerId").as[Int] == -1){
  val newId = JsObject(Seq(("customerId",JsString("ID12345"))))
  (request.body ++ newId).as[JsValue]
} else request.body

updatedJson.validate[Report](Reports.readsWithoutUser).map {
  case _: Report =>
Kokand answered 8/2, 2013 at 0:31 Comment(1)
You can't update the value in place since the Play Json data structures are immutable, but you can create a new JsValue that is identical except for the updated field.Kokand
S
1

I'm considering moving away from all of those immutable "JSON" solutions. It's just making the code a horrible mess. This is how it would look in SON of JSON:

import nl.typeset.sonofjson._

val json = …
if (json.customerId.as[Int] == -1) {
  json.customerId = 987938
}
Sixtieth answered 21/9, 2014 at 10:44 Comment(0)
F
0

a glorified version of Zeimyth's answer that uses implicit conversion

implicit class JsObjectEnhancer(jsObject: JsObject) {
  def update(args: (String, Json.JsValueWrapper)*): JsObject = {
    jsObject ++ Json.obj(args: _*)
  }
}

usage (json must be of type JsObject and the implicit class should be in scope)

json.update("customerId", 1000)
Frangible answered 3/1, 2017 at 4:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.