How do I replace a value in a JSON value in Play?
Code to illustrate:
def newReport() = Action(parse.json) { request =>
var json = request.bod
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
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)
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)
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
}
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 =>