Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse Json Objects into case classes in Scala?

Tags:

scala

circe

I have an array of Json objects. All of these objects follow one of two structures: The first like this:

{
            "uuid": "321,
            "uuidType": "series",
            "title": "a movie",
            "segments": [
                "movie"
            ],
            "seriesIds": [
                "123"
            ]
        }

And the second like this:

 {
            "uuid": "1234",
            "uuidType": "programme",
            "title": "programme title",
            "type": "movie",
            "segments": [
                "movies"
            ],
            "programmeIds": [
                "321"
            ]
        }

However, I want to parse these objects into the same case class like this:

case class SearchResult(uuid: String, uuidType: String, title: String, segments: List[String], ids: List[String])

So with the second type of object, the type key and value would be ignored, and both seriesIds from the first object and programmeIds from the second object would go into the ids part of the case class. However I have no idea how to do this! I am using Circe to decode/encode the json.

like image 810
Nespony Avatar asked Sep 18 '25 01:09

Nespony


2 Answers

You can place a custom decoder in the SearchResult object companion

scala 2.12
circe 0.9.3

import io.circe._
import io.circe.parser._

object Main extends App {

  val jsonA =
    """{
         "uuid": "321",
         "uuidType": "series",
         "title": "a movie",
         "segments": [
            "movie"
         ],
         "seriesIds": [
            "123"
         ]
       }"""

  val jsonB =
    """{
        "uuid": "1234",
        "uuidType": "programme",
        "title": "programme title",
        "type": "movie",
        "segments": [
          "movies"
        ],
        "programmeIds": [
          "321"
        ]
       }"""

  case class SearchResult(uuid: String, uuidType: String, title: String, segments: List[String], ids: List[String])

   object SearchResult {

    implicit val decoder: Decoder[SearchResult] = Decoder.instance { h =>

    for {
      uuid <- h.get[String]("uuid")
      uuidType <- h.get[String]("uuidType")
      title <- h.get[String]("title")
      segments <- h.get[List[String]]("segments")
      ids <- {
        h.getOrElse[List[String]]("seriesIds")(h.get[List[String]]("programmeIds").getOrElse(Nil))
      }
    } yield SearchResult(uuid, uuidType, title, segments, ids)

   }

  }

  val obj1 = decode[SearchResult](jsonA)
  println(obj1)

  val obj2 = decode[SearchResult](jsonB)
  println(obj2)

  }
like image 146
Sebastian Celestino Avatar answered Sep 19 '25 19:09

Sebastian Celestino


you can write custom code within circe to get the effect you want, but it seems to me it would be simpler to use circe automatic deserialization and define your case class as

case class SearchResult(uuid: String, uuidType: String, title: String, segments: List[String], programmeIds: Option[List[String]], seriesIds: Option[List[String]])

and transform that into ids using simple scala code

like image 39
Arnon Rotem-Gal-Oz Avatar answered Sep 19 '25 19:09

Arnon Rotem-Gal-Oz