8

I have the code snippet

cursor.downField("params").downField("playlist").downField("items").as[List[Clip]]

Where Clip is a simple case class of strings and numbers. The incoming Json should contain a json object "playlist" with an array of "items" where each item is a clip. So the json should look like

{
  "playlist": {
      "name": "Sample Playlist",
      "items": [
        {
          "clipId":"xyz", 
          "name":"abc"
        },
        {
          "clipId":"pqr", 
          "name":"def"
        } 
      ]
   }
}

With the code snippet above, I'm getting the compile error:

 Error:(147, 81) could not find implicit value for parameter d:     
 io.circe.Decoder[List[com.packagename.model.Clip]]
      cursor.downField("params").downField("playlist").downField("items").as[List[Clip]]

What am I doing wrong? How do you setup decoding for a list/array of simple items using circe?

3
  • can you provide a bit more context? the error is referring to a parameter d, what's that supposed to be? Commented Feb 17, 2017 at 14:45
  • I think that it is look for a decoder. In general, my question is how to decode json arrays into arrays of case class objects. Commented Feb 17, 2017 at 15:57
  • The way you are doing it seems the right way. Have you declared decoders for the Clip case class (manually or (semi)automatically)? Commented Feb 17, 2017 at 16:01

3 Answers 3

15

For the sake of completeness, instead of navigating into the JSON value and then decoding the clips, you could create a custom decoder that includes the navigation in its processing:

import io.circe.Decoder, io.circe.generic.auto._

case class Clip(clipId: String, name: String)

val decodeClipsParam = Decoder[List[Clip]].prepare(
  _.downField("params").downField("playlist").downField("items")
)

And then if you've got this:

val json = """{ "params": {
  "playlist": {
      "name": "Sample Playlist",
      "items": [
        {
          "clipId":"xyz", 
          "name":"abc"
        },
        {
          "clipId":"pqr", 
          "name":"def"
        } 
      ]
   }
}}"""

You can use the decoder like this:

scala> io.circe.parser.decode(json)(decodeClipsParam)
res3: Either[io.circe.Error,List[Clip]] = Right(List(Clip(xyz,abc), Clip(pqr,def)))

I'd probably go a step further and use a custom case class:

import io.circe.generic.auto._
import io.circe.generic.semiauto.deriveDecoder

case class Clip(clipId: String, name: String)
case class PlaylistParam(name: String, items: List[Clip])

object PlaylistParam {
  implicit val decodePlaylistParam: Decoder[PlaylistParam] =
    deriveDecoder[PlaylistParam].prepare(
      _.downField("params").downField("playlist")
    )
}

Now you can just write this:

scala> io.circe.parser.decode[PlaylistParam](json).foreach(println)
PlaylistParam(Sample Playlist,List(Clip(xyz,abc), Clip(pqr,def)))

How you want to split up the navigation and decoding is mostly a matter of taste, though.

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

2 Comments

Thank you for being so thorough in your response. In an attempt to better understand this, what does the prepare function do? When is the appropriate time to use it.
@mattmar10 If you think of a decoder as a pipe from a JSON value to some type A, prepare attaches a transformer to the input side of the pipe, so that you can transform the JSON before decoding.
3

Thanks for the help. I was able to figure it out after stepping away for awhile and coming back with fresh eyes.

I think I was going wrong by using the downArray function.

My solution was to do the following:

override def main(args: Array[String]): Unit = {
    import ClipCodec.decodeClip

    val json = parse(Source.fromFile("playlist.json").mkString).right.get
    val clips = json.hcursor.downField("params").downField("playlist")
                   .downField("items").as[Seq[Clip]]

  }

Comments

1

Circe is looking for an implicitly declared decoder for List[Clip] and cannot find it.

I suspect that you have not defined a decoder either manually or (semi)automatically. You can do both by following the official docs https://circe.github.io/circe/codec.html.

Unfortunately I cannot provide more detail than this because the question is rather vague. I will update my answer when more details are given.

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.