I'm trying to encode a list of objects using Circe, something that looks similar to:
val test = Seq(MyObject("hello", None, 1, 2, None)
I'm trying to parse this using Circe:
test.asJson
But this creates the JSON object:
[
{
name: "hello",
someVal: null,
someNum: 1,
anotherNum: 2,
anotherVal: null
}
]
I've tried running asJson
with .dropNullValues
, but that doesn't seem to access the null values inside of the object. Is there a way to drop the null values inside of the objects?
I'm expecting something more like this:
[
{
name: "hello",
someNum: 1,
anotherNum: 2
}
]
Circe provides the function deepDropNullValues
in the Json
class.
Example: test.asJson.deepDropNullValues
You see field: null
because circe turns Option[T]
to t.asJson
on Some[T]
and JsonNull
on None
, and default case class encoder just puts all fields to the JsonObject
. In a way that circe uses to encode sealed trait family, it may use these null
fields to distinguish classes like
sealed trait Foo
case class Bar(a: Option[String])
case class Baz(a: Option[String], b: Option[String])
So, if you really want to drop this information and need one-way conversion with information loss, you can map resulting Json
to drop all and every null field with code like that:
implicit val fooEnc: Encoder[Foo] = deriveEncoder[Foo].mapJsonObject{jsonObj => jsonObj.filter{case (k,v) => !v.isNull}}
However, you should write such a custom codec for any class you want to drop null fields. To post-process your json, you can use fold on resulting json:
val json: Json = ???
json.fold[Json](
Json.Null,
Json.fromBoolean,
{_.asJson},
{_.asJson},
{_.asJson},
{jsonObj => jsonObj.filter{case (k,v) => !v.isNull}.asJson}
)
or implement a custom folder.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With