Цирцея: установить для необязательного поля `null`

Есть ли способ сериализовать одно поле None в "null"?

Например:

// When None, I'd like to serialize only f2 to `null`
case class Example(f1: Option[Int], f2: Option[Int])
val printer = Printer.noSpaces.copy(dropNullValues = true)

Example(None, None).asJson.pretty(printer) === """{"f2":null}"""

person Dragisa Krsmanovic    schedule 18.03.2019    source источник


Ответы (1)


Вы можете сделать это довольно просто, сопоставив фильтр с выходом кодировщика (который может быть получен, определен с помощью Encoder.forProductN и т. д.):

import io.circe.{ Json, ObjectEncoder }
import io.circe.generic.semiauto.deriveEncoder

case class Example(f1: Option[Int], f2: Option[Int])

val keepSomeNulls: ((String, Json)) => Boolean = {
  case ("f1", v) => !v.isNull
  case (_, _) => true
}

implicit val encodeExample: ObjectEncoder[Example] =
  deriveEncoder[Example].mapJsonObject(_.filter(keepSomeNulls))

А потом:

scala> import io.circe.syntax._
import io.circe.syntax._

scala> Example(Some(1), Some(2)).asJson.noSpaces
res0: String = {"f1":1,"f2":2}

scala> Example(Some(1), None).asJson.noSpaces
res1: String = {"f1":1,"f2":null}

scala> Example(None, Some(2)).asJson.noSpaces
res2: String = {"f2":2}

scala> Example(None, None).asJson.noSpaces
res3: String = {"f2":null}

Обратите внимание, что настройка принтера для удаления нулевых значений по-прежнему удалит здесь "f2": null. Это одна из причин, по которой я думаю, что в целом лучше всего возложить ответственность за сохранение нулевых значений исключительно на принтер, но в таком случае наличие или отсутствие пустых полей явно имеет семантическое значение, поэтому вы нужно перепутать уровни.

person Travis Brown    schedule 19.03.2019
comment
Интересно, могу ли я что-то сделать с принтером, чтобы разрешить нули только для некоторых классов, а не для других. - person Dragisa Krsmanovic; 19.03.2019
comment
Если не считать написания собственного Json => String (что, безусловно, вариант), я так не думаю. - person Travis Brown; 19.03.2019