Search code examples
jsonscalaplayframework

Is there a way to map a JSON object with more then 22 keys in Scala (2.12.4) Play2 (2.6.3)?


Just a simple example, I want to map a JSON response to a Scala case class. I'm using Play2 framework 2.6.3.

case class Hobby(id:Int, name:String)
case class Person(name:String,
              name1:String,
              name2:String,
              name3:String,
              name4:String,
              name5:String,
              name6:String,
              name7:String,
              name8:String,
              name9:String,
              name10:String,
              name11:String,
              name12:String,
              name13:String,
              name14:String,
              name15:String,
              name16:String,
              name17:String,
              name18:String,
              name19:String,
              name20:String,
              nickname:Boolean, hobbies:Seq[Hobby], createdDate:LocalDateTime)

I know that I could create a reader, Reads[Person] and a Reads[Hobby], or parse manually each field like in this example: https://github.com/playframework/play-json

My question is if I can create a sort of automatic parser using a implicit value, because I have more then 22 fields, and it reaches Scala maximum Tuple22.

JSON example of Person object:

    {
  "name": "Mary",
  "name1": "Mary",
  "name2": "Mary",
  "name3": "Mary",
  "name4": "Mary",
  "name5": "Mary",
  "name6": "Mary",
  "name7": "Mary",
  "name8": "Mary",
  "name9": "Mary",
  "name10": "Mary",
  "name11": "Mary",
  "name12": "Mary",
  "name13": "Mary",
  "name14": "Mary",
  "name15": "Mary",
  "name16": "Mary",
  "name17": "Mary",
  "name18": "Mary",
  "name19": "Mary",
  "name20": "Mary",
  "nickname": true,
  "hobbies" : [
    {
      "id": 1,
      "name": "fitness",
      "createdDate": "2018-03-29T17:49:24.5304566+07:00"
    },
    {
      "id": 2,
      "name": "skating",
      "createdDate": "2018-03-29T17:49:24.5304566+07:00"
    }
  ],
  "createdDate": "2018-03-29T17:49:24.5304566+07:00"
}

I managed to reproduce the error that I got, it appears because in the JSON that I was receiving I'm exceeding the Tuple22 in Scala, that is the maximum tuple. This is the error that I was getting:

Error:(62, 44) No unapply or unapplySeq function found for class Person: <none> / <none>
      implicit val personReads = Json.reads[Person]

Solution

  • I found a library that can automatically parse more complex JSONs.

    https://circe.github.io/circe/

    For LocalDateTime I need to use this:

    implicit val encodeFoo: Encoder[LocalDateTime] = (a: LocalDateTime) => {
        Json.fromString(a.format(DateTimeFormatter.ISO_DATE_TIME))
    }
    implicit val decodeFoo: Decoder[LocalDateTime] = (c: HCursor) => {
       c.value.as[String]
        .map(LocalDateTime.parse(_, DateTimeFormatter.ISO_DATE_TIME))
    }
    

    And just use decode method on the JSON string:

    val person: Person = decode[Person](jsonStr)