Ошибки Unmarshalling JSON массив в список классов casec - PullRequest
0 голосов
/ 23 сентября 2018

Я пытался разархивировать JSON из внешнего сервиса в список классов дел, используя circe (я новичок и в 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 в список классов case?

1 Ответ

0 голосов
/ 23 сентября 2018

Определение класса case для User является действительным, но использование неявного 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)))))))

Так что еслив вашем случае это возможно, я бы предложил добавить другой специальный случай, заключающий в себе список пользователей, вместо использования пользовательского декодера.

...