Я использую Circe для десериализации json, содержащего список. Иногда несколько элементов в списке json повреждены, что приводит к сбою всей десериализации. Вместо этого я хочу, чтобы Цирце сделал лучшую попытку и вернул список всех успешно десериализованных элементов списка вместе со списком ошибок для поврежденных элементов. Как это лучше всего сделать в Цирцее?
В частности, допустим, я пытаюсь десериализовать это:
val json = """{ "params": {
"playlist": {
"name": "Sample Playlist",
"items": [
{
"clipId":"xyz",
"name":"abc",
"properties": {
"cat": "siamese",
"dog": "spaniel"
}
},
{
"clipId":"pqr",
"name":"def",
"properties": {
"cat": "tabby",
"dog": "terrier"
}
}
]
}
}}"""
Я делаю это с:
import io.circe.Decoder, io.circe.generic.auto._
import scala.util._
case class Clip(clipId: String, name: String, dog: String)
implicit val decodeClip: Decoder[Clip] = Decoder.instance { c =>
for {
id <- c.get[String]("clipId")
name <- c.get[String]("name")
dog <- c.downField("properties").get[String]("dog")
} yield {
Clip(id, name, dog)
}
}
val decodeClipsParam = Decoder[List[Clip]].prepare(
_.downField("params").downField("playlist").downField("items")
)
def deserializedThing(theJson: String) = io.circe.parser.decode(theJson)(decodeClipsParam)
Отлично работает и десериализуется правильно:
scala> deserializedThing(json)
res1: Either[io.circe.Error,List[circeLab.circeLab.Clip]] = Right(List(Clip(xyz,abc,spaniel), Clip(pqr,def,terrier)))
Но если я теперь испорчу один элемент списка json (изменив один из ключей "dog"
на "doggg"
скажем), то вся десериализация завершится неудачей - это не даст мне список не поврежденных Clip
элементы, это просто говорит мне, что это не удалось.
Так что вместо десериализации в List[Clip]
я бы хотел десериализовать в List[Try[Clip]]
, где каждый элемент похож на Success(Clip(xyz,abc,spaniel))
или Failure(ErrorDescriptionForThatItem)
.
Мне удалось добиться этого в Argonaut (используя довольно некрасивый код), но я не могу понять синтаксис в Circe. Какой лучший способ достичь этого?
Спасибо!