使用Argonaut/Circe解码JSON数组中的单个字段

4
假设我有这样的JSON:
{
  "sha": "some sha",
  "parents": [{
    "url": "some url",
    "sha": "some parent sha"
  }]
}

和这样的case类

case class Commit(sha: String, parentShas: List[String])

在play-json中,我可以这样编写读取器:

val commitReads: Reads[Commit] = (
  (JsPath \ "sha").read[String] and
  (JsPath \ "parents" \\ "sha").read[List[String]]
)(Commit.apply _)

我正在寻找一种等效的方法,仅解码argonaut/circe中“parent”的“sha”,但我没有找到任何方法。“HCursor/ACursor”具有downArray,但从那里开始,我不知道该怎么做。非常感谢您提前的帮助!

1个回答

3

无论是Circe还是Argonaut都无法跟踪JSON对象中已读取的字段,因此您可以忽略额外的"url"字段(就像在Play中一样)。更棘手的部分是找到Play的“\\”的等效项,目前circe没有这个功能,尽管您已经说服我我们需要添加。

首先,如果您有一个单独的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)
}

或者,使用Cats的应用语法:

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)
}

这很糟糕,我感到羞愧因为需要这么做,但它有效。我刚刚提交了一个问题,以确保在未来的circe版本中改进这一点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接