Oscar Godson Oscar Godson - 1 year ago 83
Scala Question

Add key/value to existing JsValue in Scala

I'm new to Scala and I'm trying to figure out how I would add a key/value to a JsValue. In JavaScript you might do something like

SomeObject.newKey = newValue
. Here's my real use case:

def doAccountUpdate(account: db.models.Account, config: JsObject, job: JsValue) : JsValue = {
val passwordParam = (job \ "params" \ "password")
if (passwordParam.toOption.isDefined) {
val password = (job \ "params" \ "password").get.as[String]
val encrypted_password = Auth.passwordEncrypt(password)
// ADD `encrypted_password`'s value TO `job \ params` so its `job \ params \ encryptedPassword`

Account.update(account, config, job)

actually updates the DB so in my
i'm prepping the data. One of those items I need to prep is password by encrypting it before passing it to
. How do I do this?


To explain why the question this is marked a duplicate of doesn't work for me is this is their example:

jsonObject.as[JsObject] + ("c" -> Json.toJson(3))

If I duplicate that in my code it would look like this:

updateJob = job.as[JsObject] + ("encryptedPassword" -> Json.toJson(encrypted_password))

but that outputs:

"params": {

Note how
isn't in

Answer Source

As @danielnixon suggests, you can use JSON transformers for this. Here is an example:

val encryptPassword: Reads[JsObject] = (__ \ "params").json.update(
  (__ \ "password").read[String].flatMap(pw =>
    (__ \ "encryptedPassword").json.put(JsString(Auth.passwordEncrypt(pw)))

This says we will:

  1. update the params object
  2. read the existing password
  3. put a new encryptedPassword branch in the params object

When you apply that with job.transform(encryptPassword) you'll get a JsResult that, if the params object exists and has a password field with a string value, will be JsSuccess - otherwise you'll get JsError. You can handle that with something like the following:

def doAccountUpdate(account: db.models.Account, config: JsObject, job: JsValue) : JsValue = {
  job.transform(encryptPassword) match {
    case JsSuccess(newJob, _) => Account.update(account, config, newJob)
    case JsError(errors) => sys.error("No password supplied!")