How to Use Circe for Decoding JSON Lists/Arrays in Scala

牧云@^-^@ 提交于 2019-12-05 10:02:27

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.

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]]

  }

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.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!