0
votes

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]
2
Not clear, give examplescchantep
Yes, you are right. Totally forgot abut an example.Robert Gabriel
Still unclear what's the problemcchantep
The problem is that I have to manually parse each field. Coming from Java where you just need annotations to a POJO, this feels like reinventing the wheel. Nvm I found a library, I'll post an answer.Robert Gabriel
So, if more then 22 parameters in case class Play JSON library breaks.Robert Gabriel

2 Answers

1
votes

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)
0
votes

You don't have to manually create the implicit Reads/Writes objects. Play JSON library handles that.

Deserialize JSON String to object:

import play.api.libs.json._

case class Hobby(id:Int, name:String)
case class Person(name:String, nickname:String, hobbies:Seq[Hobby], createdDate:LocalDate)

implicit val hobbyReads = Json.reads[Hobby]
implicit val personReads = Json.reads[Person]

val person: Person = Json.parse(jsonString).as[Person]

Serialize back to JSON String:

implicit val hobbyWrites = Json.writes[Hobby]
implicit val personWrites = Json.writes[Person]

Json.toJson(person).toString()

Writing a custom Reads/Writes would only be required if you need to make a custom calculation/manipulation on the input.