I am having a case class that has more than 22 parameters.
case class Model(a1: Int,
a2: Int,
a3: Int,
a4: Int,
a5: Int,
a6: Int,
a7: Int,
a8: Int,
a9: Int,
a10: Int,
a11: Int,
a12: Int,
a13: Int,
a14: Int,
a15: Int,
a16: Int,
a17: Int,
a18: Int,
a19: Int,
a20: Int,
a21: Int,
a22: Int,
a23: Int,
a24: Int)
I am getting a json input which I need to de-serialize to the above Model
case class. But, my input json does not contain the fields a1 and a2. My json looks something like this
{
"a3": 3,
"a4": 4,
"a5": 5,
"a6": 6,
"a7": 7,
"a8": 8,
"a9": 9,
"a10": 10,
"a11": 11,
"a12": 12,
"a13": 13,
"a14": 14,
"a15": 15,
"a16": 16,
"a17": 17,
"a18": 18,
"a19": 19,
"a20": 20,
"a21": 21,
"a22": 22,
"a23": 23,
"a24": 24
}
Now, to cater to this situation, I wrote my custom json reader which would add some dummy values for the fields a1 and a2 in the json.
I have a custom method to add fields to the input json that is read. Extension method addField
is as follows
implicit class ReadOps[A](reads: Reads[A]) {
def addField(fieldName: String, value: Int): Reads[A] = Reads {
json: JsValue =>
json
.validate(__.json.update((__ \ fieldName).json.put(JsString(value.toString))))
.map(_.asInstanceOf[A])
}
}
My implicit json format is as follows
implicit val jsonFormat = new OFormat[Model] {
override def reads(json: JsValue): JsResult[Model] = {
Jsonx.formatCaseClass[Model].addField("a1",1).addField("a2",2).reads(json)
}
override def writes(o: Model): JsObject = {
Jsonx.formatCaseClass[Model].writes(o)
}
}
Problem that I am facing
Inspite of calling the method addField twice (I am trying to add a1 with value 1 and a2 with value 2), only the field a1
with value 1
gets added to the json and a2 is ignored. And the json does not get de-serialized to the model case class.
I am using the following dependency
libraryDependencies += "ai.x" %% "play-json-extensions" % "0.30.1"
Please let me know where I am going wrong in this approach. Any pointers will be very helpful. Thanks in advance !!!
Note:- Please don't suggest solutions like adding a1 and a2 as fields in the model case class. This is out of question as my actual problem is quite complicated and this question on stackoverflow is a very simplified version of the problem at hand.
Consider adding a field in a new branch via JsPath.update
:
val js = Json.obj("key1" -> "value1", "key2" -> "value2") js.validate(__.json.update((__ \ 'key3).json.put(JsString("value3")))) => JsSuccess({"key1":"value1","key2":"value2","key3":"value3"},)
Here is a working example
import ai.x.play.json.Jsonx
import play.api.libs.json.Json
import play.api.libs.json._
case class Foo(a1: Int, a2: Int, a3: Int, a4: Int, a5: Int, a6: Int, a7: Int, a8: Int, a9: Int, a10: Int, a11: Int, a12: Int, a13: Int, a14: Int, a15: Int, a16: Int, a17: Int, a18: Int, a19: Int, a20: Int, a21: Int, a22: Int, a23: Int, a24: Int)
object Foo {
implicit val format = Jsonx.formatCaseClass[Foo]
}
object AddFieldsToDeserialisation extends App {
val raw =
"""
|{
| "a3": 3,
| "a4": 4,
| "a5": 5,
| "a6": 6,
| "a7": 7,
| "a8": 8,
| "a9": 9,
| "a10": 10,
| "a11": 11,
| "a12": 12,
| "a13": 13,
| "a14": 14,
| "a15": 15,
| "a16": 16,
| "a17": 17,
| "a18": 18,
| "a19": 19,
| "a20": 20,
| "a21": 21,
| "a22": 22,
| "a23": 23,
| "a24": 24
|}
""".stripMargin
val json = Json.parse(raw)
val updatePutTransformation =
(field: String, value: Int) => __.json.update((__ \ field ).json.put(JsNumber(value)))
val addedFields =
List("a1" -> 1, "a2" -> 2)
.map { case (field, value) => updatePutTransformation(field, value) }
.reduce((putUpdate1, putUpdate2) => putUpdate1 andThen putUpdate2 )
val jsonWithPutValue = json.transform(addedFields)
println(jsonWithPutValue.get)
println(jsonWithPutValue.get.as[Foo])
}
should output
{ "a1": 1, "a2": 2, "a3": 3, "a4": 4, "a5": 5, "a6": 6, "a7": 7, "a8": 8, "a9": 9, "a10": 10, "a11": 11, "a12": 12, "a13": 13, "a14": 14, "a15": 15, "a16": 16, "a17": 17, "a18": 18, "a19": 19, "a20": 20, "a21": 21, "a22": 22, "a23": 23, "a24": 24 }
Foo(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24)