3

In continuation of this question, I have the following code but would like to map null JSON values to Scala None. Current behavior I am getting is that there's no difference between including a key with null ("key": null) and not including it. I would like to map this to None so I can set the DB entry to null. Also, when a key is not included in the JSON, map it to existing value.

import io.circe.jawn.decode, io.circe.generic.auto._

case class Person(name: String, age: Int, description: Option[String])

val existingPerson = Person("mr complete", 42, Some("tall and fat"))
val incompletePersonJson = """{"description":null}"""

val update = decode[Person => Person](incompletePersonJson)

And then:

scala> println(update.map(_(existingPerson)))
Right(Person(mr updated,42,Some(tall and fat)))

But I would like to get:

Right(Person(mr updated,42,None))
FrozenHG
  • 45
  • 4

1 Answers1

0

I ended up with the following solution, it might be not ideal and it's not using Circe but it does the job for me:

def getJsonNullKeys(json: Json): List[String] = {
  json.asObject match {
    case Some(jsonObject) => jsonObject.filter(j => j._2.isNull).keys.toList
      case None => List[String]()
    }
}

if (update.isRight) {
  update.right.map(_(existingPerson)) match {
    case Right(updatedPerson) =>
      getNullKeys(incompletePersonJson).foreach { key =>
        val field = existingPerson.getClass.getDeclaredField(key)
        field.setAccessible(true)
        field.set(updatedUpdate, None)
      }
      println(updatedUpdate)
      // outputs Person(mr updated,42,None)
    case Left(error) => println(error.toString)
  }
}

Hope Circe adds support for this so all this boilerplate can be removed.

FrozenHG
  • 45
  • 4