简体   繁体   English

如何使用Circe解码Scala中的JSON列表/数组

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

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. Clip是一个简单的字符串和数字类。 The incoming Json should contain a json object "playlist" with an array of "items" where each item is a clip. 传入的Json应该包含一个json对象“播放列表”,其中包含一个“项目”数组,其中每个项目都是一个剪辑。 So the json should look like 所以json看起来应该是这样的

{
  "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? 如何使用circe为简单项目的列表/数组设置解码?

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: 为了完整起见,您可以创建一个自定义解码器,在其处理中包含导航,而不是导航到JSON值然后解码剪辑:

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. 我认为使用downArray函数我出错了。

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. Circe正在为List[Clip]寻找隐式声明的解码器,但无法找到它。

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 . 您可以按照官方文档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. 当给出更多细节时,我会更新我的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM