使用 circe 解码 JSON 对象时捕获未使用的字段
Posted
技术标签:
【中文标题】使用 circe 解码 JSON 对象时捕获未使用的字段【英文标题】:Capturing unused fields while decoding a JSON object with circe 【发布时间】:2018-12-23 21:17:22 【问题描述】:假设我有一个像下面这样的案例类,我想将一个 JSON 对象解码到其中,所有未使用的字段都以一个特殊的成员结尾:
import io.circe.Json
case class Foo(a: Int, b: String, leftovers: Json)
在 Scala 中使用 circe 执行此操作的最佳方法是什么?
(注意:我已经看到类似a few times 的问题,所以我正在为后代答疑解惑。)
【问题讨论】:
【参考方案1】:有几种方法可以解决这个问题。一种相当直接的方法是过滤掉解码后使用的密钥:
import io.circe. Decoder, Json, JsonObject
implicit val decodeFoo: Decoder[Foo] =
Decoder.forProduct2[Int, String, (Int, String)]("a", "b")((_, _)).product(
Decoder[JsonObject]
).map
case ((a, b), all) =>
Foo(a, b, Json.fromJsonObject(all.remove("a").remove("b")))
如您所愿:
scala> val doc = """ "something": false, "a": 1, "b": "abc", "0": 0 """
doc: String = "something": false, "a": 1, "b": "abc", "0": 0
scala> io.circe.jawn.decode[Foo](doc)
res0: Either[io.circe.Error,Foo] =
Right(Foo(1,abc,
"something" : false,
"0" : 0
))
这种方法的缺点是您必须维护代码以将您使用过的密钥与其使用分开,这很容易出错。另一种方法是使用 circe 的 state-monad-powered 解码工具:
import cats.data.StateT
import cats.instances.either._
import io.circe. ACursor, Decoder, Json
implicit val decodeFoo: Decoder[Foo] = Decoder.fromState(
for
a <- Decoder.state.decodeField[Int]("a")
b <- Decoder.state.decodeField[String]("b")
rest <- StateT.inspectF((_: ACursor).as[Json])
yield Foo(a, b, rest)
)
它的工作方式与之前的解码器相同(除了在解码失败时会出现一些小的错误差异):
scala> io.circe.jawn.decode[Foo](doc)
res1: Either[io.circe.Error,Foo] =
Right(Foo(1,abc,
"something" : false,
"0" : 0
))
后一种方法不需要您在多个位置更改已使用的字段,而且它还具有看起来更像您在circe 中手动编写的任何其他解码器的优点。
【讨论】:
以上是关于使用 circe 解码 JSON 对象时捕获未使用的字段的主要内容,如果未能解决你的问题,请参考以下文章
无法使用Circe JSON解析器创建遍历JSON字符串的对象