It's possible to have a class that looks like so:
case class Amount(value: Int)
case class Data(insurance: Option[Amount], itemPrice: Amount)
If insurance = None
it should get a default value of waived: true
E.g:
Data(Some(123),100).asJson
// output
{
"insurance": {
"value": 123
},
"price": 100
}
And when no Insurance is opted for:
Data(None,100).asJson
// output
{
"insurance": {
"waived: true
},
"price": 100
}
How can this fine-grained control be achieved? I tried various tricks with forProduct2
and mapJsonObject
but couldn't get it to behave right:
implicit val testEncoder = deriveEncoder[Option[Amount]].mapJsonObject(j => {
val x = j("Some") match {
case Some(s) => // need to convert to [amount -> "value"]
case None => JsonObject.apply(("waived",Json.fromBoolean(true)))
}
x
})
This can easily get me the waived:true
part but no idea how to handle the Some(s)
case.
If having {"waived": true}
is expected behavior for any Option[Amount]
if it's None, then you can rely on semiauto derived encoders if you write your custom encoder for Option[Amount]
Here is an example
import io.circe.{Encoder, Json}
import io.circe.syntax._
import io.circe.generic.semiauto._
case class Amount(value: Int)
case class Data(insurance: Option[Amount], itemPrice: Amount)
object Amount {
implicit val encoder: Encoder[Amount] = deriveEncoder
}
object Data {
implicit val encoderOptionalAmount: Encoder[Option[Amount]] = (optA: Option[Amount]) =>
optA match {
case Some(amount) => amount.asJson
case None => Json.obj("waived" -> true.asJson)
}
implicit val encoder: Encoder[Data] = deriveEncoder[Data]
}
println(Data(insurance = None, itemPrice = Amount(10)).asJson)
/*
{
"insurance" : {
"waived" : true
},
"itemPrice" : {
"value" : 10
}
}
*/
How it works: deriveEncoder[Data]
will call implicit encoders for both itemPrice (of type Amount
) and insurance of type Option[Amount]
.
Default encoder for Option[T]
just skips the value if it's None
but since we defined another implicit encoder for Option[T]
in the closest scope (Data object-companion) it won't look for implicit encoders in global scopes giving you exactly what you want.