Search code examples
scalaplayframeworkplay-json

how to change json field value in the json level with Play json?


I have a simple case class that im working with in my app, and at some point im changing it to json and sending it to some api call, like this:

import play.api.libs.json.{Json, OFormat}

object MyClassSer {
  implicit val MyClassFormat: OFormat[MyClass] = Json.format[MyClass]
}

import MyClassSer._

case class MyClass(a: String, b: String)

val myClass = MyClass("1", "2")

myApiService.post(Json.toJson(myClass))

I wonder if there is a way to change b in the json to Int if I know it always gonna be an int value (but in MyClass unfortunately it has to be string)?

so instead of {"a": "1", "b": "2"} I will send {"a": "1", "b": 2}

can I do this with JsValue somehow or JsObject? I dont want to have another case class and transform it to the other case class..


Solution

  • Use custom writes rather than the default Json.format.....:

    import play.api.libs.json.{Json, _}
    
    object MyClass {
      implicit val format: OFormat[MyClass] = Json.format[MyClass]
    
      implicit val customwrites: Writes[MyClass] = new Writes[MyClass] {
        def writes(myClass: MyClass): JsValue = Json.obj(
          "a" -> myClass.a,
          "b" -> myClass.b.toInt
        )
      }
    }
    
    case class MyClass(a: String, b: String)
    
    val myClass = MyClass("1", "2")
    
    // use default writes implicitly
    println(Json.toJson(myClass)) // {"a":"1","b":"2"}
    
    // use non-default writes explicitly
    println(Json.toJson(myClass)(MyClass.customwrites)) // {"a":"1","b":2}
    

    Though I would be careful about converting types like you want to without some sort of fallback, just in case the value isn't an Int.