如何使用 Circe 创建 Option 类型的自定义编码?
How to create custom encoding of Option types with Circe?
有可能 class 看起来像这样:
case class Amount(value: Int)
case class Data(insurance: Option[Amount], itemPrice: Amount)
如果 insurance = None
它应该得到默认值 waived: true
例如:
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
}
如何实现这种细粒度的控制?我尝试了 forProduct2
和 mapJsonObject
的各种技巧,但无法使其正常运行:
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
})
这很容易让我得到 waived:true
的部分,但不知道如何处理 Some(s)
的情况。
如果 {"waived": true}
是任何 Option[Amount]
的预期行为,如果它是 None,那么如果您为 Option[Amount]
编写自定义编码器,则可以依赖半自动派生编码器
这是一个例子
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
}
}
*/
工作原理:deriveEncoder[Data]
将为 itemPrice(Amount
类型)和 Option[Amount]
类型的保险调用隐式编码器。
Option[T]
的默认编码器只是跳过 None
的值,但由于我们在最近的范围(数据对象伴侣)中为 Option[T]
定义了另一个隐式编码器,它不会'不要在全局范围内寻找隐式编码器,为您提供您想要的东西。
有可能 class 看起来像这样:
case class Amount(value: Int)
case class Data(insurance: Option[Amount], itemPrice: Amount)
如果 insurance = None
它应该得到默认值 waived: true
例如:
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
}
如何实现这种细粒度的控制?我尝试了 forProduct2
和 mapJsonObject
的各种技巧,但无法使其正常运行:
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
})
这很容易让我得到 waived:true
的部分,但不知道如何处理 Some(s)
的情况。
如果 {"waived": true}
是任何 Option[Amount]
的预期行为,如果它是 None,那么如果您为 Option[Amount]
编写自定义编码器,则可以依赖半自动派生编码器
这是一个例子
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
}
}
*/
工作原理:deriveEncoder[Data]
将为 itemPrice(Amount
类型)和 Option[Amount]
类型的保险调用隐式编码器。
Option[T]
的默认编码器只是跳过 None
的值,但由于我们在最近的范围(数据对象伴侣)中为 Option[T]
定义了另一个隐式编码器,它不会'不要在全局范围内寻找隐式编码器,为您提供您想要的东西。