将 JSON 数组解组到案例类列表时出错 c

Errors Unmarshalling JSON array to List of case classesc

我一直在尝试使用 circe 将 JSON 从外部服务解编为案例列表 classes(我是 circecirce 的初学者斯卡拉)。

案例class如下:

case class User(
  id:            Int,
  username:      Option[String],
  permalink_url: Option[String],
  avatar_url:    Option[String],
  tracks:        Option[List[Track]],
  favorites:     Option[List[Track]],
  followings:    Option[List[User]] // The JSON below would populate this field
)

到目前为止,我对所有其他类型都使用了自动派生,但是这个使用了结构

   {
      "collection": [
          {
            "id": 42,
            "username": "user",
            "permalink_url": "foo://bar.baz",
            "followers_count": 15089,
            "followings_count": 498,
            "reposts_count": 31,
            "comments_count": 13,
            "online": false,
            "likes_count": 0,
            "playlist_count": 10
        },
        ...etc, etc
      ]
    }

为了解决这个问题,我实现了一个自定义解码器:

implicit val followingsDecoder: Decoder[List[User]] = Decoder.instance( c =>
    for {
      collection <- c.downField("collection").as[List[User]]
    } yield collection
)

这会失败并产生以下错误:

DecodingFailure(CNil, List(DownField(collection)))

我也尝试过使用 circe 的自动解码器推导,这会产生不同的错误:

DecodingFailure(CanBuildFrom for A, List())

我了解 circe 的错误消息未提供解码失败的字段。我不需要 User 案例 class 中未指定的任何字段,并且不确定这是否与我收到的 JSON 或我的方式有关试图解码它。

这里有我遗漏的东西吗?我已经尝试了其他解码方法,例如半自动推导以及尝试将列表解组到它自己的案例 class 中。

  implicit val followingsDecoder: Decoder[List[User]] = deriveDecoder[List[User]].prepare(
      _.downField("collection")
  )

我在这里遗漏了什么吗?我如何将此 JSON 解析为案例列表 classes?

User 的大小写 class 定义是有效的,但使用隐式 followingsDecoder: Decoder 不是强制解组的。 collection 也可以包装成 case class 并且解码将自动完成。所以,如果我们有

case class UsersCollection(collection: List[User])

// I also added this one to make it compile:
case class Track(id: Int)

和原始 json,添加了 followings 字段:

private val json =
  """
    |{
    |      "collection": [
    |          {
    |            "id": 42,
    |            "username": "user",
    |            "permalink_url": "foo://bar.baz",
    |            "followers_count": 15089,
    |            "followings_count": 498,
    |            "reposts_count": 31,
    |            "comments_count": 13,
    |            "online": false,
    |            "likes_count": 0,
    |            "playlist_count": 10,
    |            "followings": [
    |             { "id": 43 },
    |             { "id": 44 },
    |             { "id": 45 }
    |            ]
    |        }
    |      ]
    |    }
  """.stripMargin

正确解析:

val decoded = decode[UsersCollection](json)
println(decoded)

// Right(UsersCollection(List(
//  User(42,Some(user),Some(foo://bar.baz),None,None,None,
//       Some(List(User(43,None,None,None,None,None,None),
//                 User(44,None,None,None,None,None,None),
//                 User(45,None,None,None,None,None,None)))))))

因此,如果您的情况可行,我建议添加另一个临时案例 class 包装用户列表,而不是使用自定义解码器。