Reputation: 462
I am trying to use Circe to do some JSON encoding as follows:
import io.circe.{Encoder, Json}
import io.circe.syntax._
case class Person(name: String, nickname: Option[String] = None)
object EncodingTest extends App {
val persons = List (Person("John", None), Person("Tania", Some("Awesome")))
implicit val encodePerson: Encoder[Person] = (p: Person) => {
Json.obj(
("name", Json.fromString(p.name)),
("nickname", Json.fromString(p.nickname.getOrElse(""))) // <- Problem is here
)
}
for(person <- persons)
println(person.asJson)
}
Ideally, I would like to have the following output:
{"name":"John"}
{"name":"Tania","nickname":"Awesome"}
How can I make the encoder skip the nickname
field in case the field value is None
?
Upvotes: 2
Views: 3290
Reputation: 7275
If you want to define custom encoders and not rely on semiauto the following works
import io.circe.{Encoder, Json}
import io.circe.syntax._
object CirceOptional extends App {
case class Person(name: String, nickname: Option[String] = None)
val encodePerson: Encoder[Person] = (p: Person) => {
Json.obj(("name", p.name.asJson), ("nickname", p.nickname.asJson))
}
implicit val noNullEncoder: Encoder[Person] = encodePerson.mapJson(_.dropNullValues)
val persons = List (Person("John", None), Person("Tania", Some("Awesome")))
for(person <- persons)
println(person.asJson)
}
Upvotes: 4
Reputation: 5073
The easy way would be to just collect fields you are interested in
Json.obj(List(
("name", Some(Json.fromString(p.name))),
("nickname", p.nickname.map(Json.fromString))
).collect {
case (name, Some(value)) => name -> value
}: _*)
More automatic way to get what you want:
import io.circe.generic.semiauto._
implicit val encodePerson: Encoder[Person] = deriveEncoder
person.asJson.dropNullValues
Upvotes: 2