Saurabh Tewari
Saurabh Tewari

Reputation: 331

How to decode a nested json into a List[Object] using Circe in Scala

I have a json that looks somewhat like this:

{
    "results": {
        "result_1": {
            "text": "abc"
        },
        "result_2": {
            "text": "def"
        }
    }
}

I wish to decode it to a case class that looks like:

case class Results(results: List[SingleResult])

case class SingleResult(text: String)

I wish to write a decoder for this but my current decoder isn't compiling. It looks like this:

implicit val singleResultDecoder: Decoder[SingleResult] = deriveDecoder[SingleResult]
implicit val ResultsDecoder: Decoder[Results] = new Decoder[Results] {
    override def apply(c: HCursor): Result[Results] = {
        for {
            results <- c.keys.map(_.map(k => c.downField(k).as[SingleResult]).toList)
        } yield Results(results = results)
    }
}

The compilation error is:

Type mismatch : 
Required: scala.List[SingleResult]
Found: scala.List[Result[SingleResult]]

Any directions on how to fix the error would be appreciated.

Upvotes: 0

Views: 641

Answers (1)

Tomer Shetah
Tomer Shetah

Reputation: 8539

You are mixing few things here. In your json, you don't have a list, as you are trying to read it. You have a map. Therefore we need to have our Decoder accordingly:

implicit val ResultsDecoder: Decoder[Results] = new Decoder[Results] {
  override def apply(c: HCursor): Result[Results] = {
    for {
      results <- c.downField("results").as[Map[String, SingleResult]]
    } yield Results(results = results.values.toList)
  }
}

Then calling:

val decodedFoo = circe.jawn.decode[Results](jsonString)
println(decodedFoo)

results in:

Right(Results(List(SingleResult(abc), SingleResult(def))))

Code run in Scastie.

Upvotes: 2

Related Questions