4

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.

1
  • Try using circe cursors to populate the ids field into the parsed Json AST before turning it into your type. Commented Aug 11, 2018 at 14:25

2 Answers 2

3

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)

  }
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! This is exactly what I was looking for!
3

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.