2017-02-17 61 views
2

数组我的代码片断如何使用瑟茜用于解码JSON列表/斯卡拉

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

凡剪辑是一个简单的案例类字符串和数字。传入的Json应该包含一个json对象“播放列表”和一个“项目”数组,其中每个项目都是一个剪辑。因此,JSON看起来应该像

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

通过上面的代码片段,我得到的编译错误:

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

我在做什么错?如何使用circe为简单项目的列表/数组设置解码?

+0

你能否提供更多的上下文?错误是指参数'd',那应该是什么? – acidghost

+0

我认为它是寻找一个解码器。一般来说,我的问题是如何将json数组解码为case类对象的数组。 – mattmar10

+0

你这样做的方式似乎是正确的方式。你是否为Clip Case类声明了解码器(手动或(半)自动)? – acidghost

回答

7

为了完整起见,而不是导航到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") 
) 

然后,如果你有这样的:

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

您可以使用这样的解码器:

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

我可能会走了一步,并使用自定义的情况下类:

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") 
    ) 
} 

现在你可以这样写:

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

尽管如此,你想分离导航和解码主要是品味的问题。

+1

谢谢你在回复中如此详尽。为了更好地理解这一点,准备功能做了什么?什么时候适合使用它? – mattmar10

+1

@ mattmar10如果您认为解码器是从JSON值到某种类型'A'的管道,'prepare'会将一个变换器附加到管道的输入端,以便在解码之前转换JSON。 –

1

Circe正在寻找隐含声明的解码器List[Clip]并找不到它。

我怀疑你还没有手动或(半)自动定义解码器。您可以通过遵循官方文档https://circe.github.io/circe/codec.html来做到这一点。

不幸的是我不能提供比这更多的细节,因为这个问题相当模糊。在给出更多细节时,我会更新我的答案。

1

感谢您的帮助。在离开一段时间之后,我能够发现它并用新鲜的眼睛回来。

我想我使用downArray函数出错了。

我的解决办法是做到以下几点:

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

    }