Ни цирц, ни аргонавт не отслеживает, какие поля были прочитаны в объектах JSON, поэтому вы можете просто игнорировать дополнительное поле "url"
(как в Play). Более сложная часть - найти эквивалент Play's \\
, которого нет на данный момент, хотя вы убедили меня, что нам нужно добавить его.
Прежде всего, это относительно легко, если у вас есть отдельный тип Sha:
import io.circe.Decoder
val doc = """
{
"sha": "some sha",
"parents": [{
"url": "some url",
"sha": "some parent sha"
}]
}
"""
case class Sha(value: String)
object Sha {
implicit val decodeSha: Decoder[Sha] = Decoder.instance(_.get[String]("sha")).map(Sha(_))
}
case class Commit(sha: Sha, parentShas: List[Sha])
object Commit {
implicit val decodeCommit: Decoder[Commit] = for {
sha <- Decoder[Sha]
parents <- Decoder.instance(_.get[List[Sha]]("parents"))
} yield Commit(sha, parents)
}
Или, используя аппликативный синтаксис кошек'S:
import cats.syntax.cartesian._
implicit val decodeCommit: Decoder[Commit] =
(Decoder[Sha] |@| Decoder.instance(_.get[List[Sha]]("parents"))).map(Commit(_, _))
И потом:
scala> import io.circe.jawn._
import io.circe.jawn._
scala> decode[Commit](doc)
res0: cats.data.Xor[io.circe.Error,Commit] = Right(Commit(Sha(some sha),List(Sha(some parent sha))))
Но на самом деле это не ответ, так как я не прошу вас менять свою модель. :) Фактический ответ немного меньше удовольствия:
case class Commit(sha: String, parentShas: List[String])
object Commit {
val extractSha: Decoder[String] = Decoder.instance(_.get[String]("sha"))
implicit val decodeCommit: Decoder[Commit] = for {
sha <- extractSha
parents <- Decoder.instance(c =>
c.get("parents")(Decoder.decodeCanBuildFrom[String, List](extractSha, implicitly))
)
} yield Commit(sha, parents)
}
Это плохо, и мне стыдно, что это необходимо, но это работает. Я только что подал an issue, чтобы убедиться, что это улучшится в будущем выпуске circe.