如何使用 Circe 删除对象列表中的空值

How to remove null values in list of objects using Circe

我正在尝试使用 Circe 对对象列表进行编码,类似于:

val test = Seq(MyObject("hello", None, 1, 2, None)

我正在尝试使用 Circe 解析它:

test.asJson

但这会创建 JSON 对象:

[
  {
    name: "hello",
    someVal: null,
    someNum: 1,
    anotherNum: 2,
    anotherVal: null
  }
]

我试过 运行 asJson.dropNullValues,但这似乎无法访问对象内部的空值。有没有办法删除对象中的空值?

我期待更多像这样的东西:

[
  {
    name: "hello",
    someNum: 1,
    anotherNum: 2
  }
]

你看到 field: null 因为 circe 在 Some[T] 上将 Option[T] 变为 t.asJson,在 None 上将 JsonNull 变为 JsonNull,默认情况下 class 编码器只是将所有字段放入 JsonObject。在 circe 用于编码密封特征家族的方式中,它可以使用这些 null 字段来区分 class 像

sealed trait Foo
case class Bar(a: Option[String])
case class Baz(a: Option[String], b: Option[String])

因此,如果您真的想要删除此信息并且需要在信息丢失的情况下进行单向转换,您可以映射结果Json以删除所有和每个空值带有这样代码的字段:


implicit val fooEnc: Encoder[Foo] = deriveEncoder[Foo].mapJsonObject{jsonObj => jsonObj.filter{case (k,v) => !v.isNull}}

但是,您应该为要删除空字段的任何 class 编写这样的自定义编解码器。要 post 处理您的 json,您可以对结果 json 使用折叠:

  val json: Json = ???
  json.fold[Json](
    Json.Null,
    Json.fromBoolean,
    {_.asJson},
    {_.asJson},
    {_.asJson},
    {jsonObj => jsonObj.filter{case (k,v) => !v.isNull}.asJson}
  )

或实施自定义文件夹。

Circe 在 Json class 中提供函数 deepDropNullValues

示例:test.asJson.deepDropNullValues

@iva-kmm建议的答案很好,但可以做得更好!

这个机制已经是 implemented in circe,就叫它:

implicit val fooEnc: Encoder[Foo] = deriveEncoder[Foo].mapJson(_.dropNullValues) // or _.deepDropNullValues