【问题标题】:Errors Unmarshalling JSON array to List of case classesc将 JSON 数组解组为案例类列表时出错
【发布时间】:2018-09-23 14:39:53
【问题描述】:

我一直在尝试使用 circe 将 JSON 从外部服务解组为案例类列表(我是 circe 和 Scala 的初学者)。

案例类如下:

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 案例类中未指定的任何字段,并且不确定这是我收到的 JSON 的问题,还是我尝试解码它的方式的问题。

这里有什么我想念的吗?我尝试过其他解码方式,例如半自动推导,以及尝试将列表解组为自己的案例类。

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

这里有什么我错过的吗?如何将此 JSON 解析为案例类列表?

【问题讨论】:

    标签: json scala circe


    【解决方案1】:

    User 的 case 类定义是有效的,但使用隐式 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)))))))
    

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

    【讨论】:

      猜你喜欢
      • 2021-09-10
      • 1970-01-01
      • 1970-01-01
      • 2016-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多