Stratos K
Stratos K

Reputation: 462

Scala & Circe: JSON encoding with optional fields

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

Answers (2)

Ivan Stanislavciuc
Ivan Stanislavciuc

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

bottaio
bottaio

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

Related Questions