Here's what I intend - let's say I have a field called medical_payments - it can "either" be a limit if one elects or waived
{
"medical_payments":
{
"limit_value":"one_hundred"
}
}
Run Code Online (Sandbox Code Playgroud)
如果被选为豁免,则应为:
{
"medical_payments":
{
"waived":true
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,这是我所拥有的:
sealed trait LimitOrWaiver
case class Limit(limit_key: String) extends LimitOrWaiver
case class Waived(waived: Boolean) extends LimitOrWaiver
case class Selection(medical_payments: LimitOrWaiver)
Run Code Online (Sandbox Code Playgroud)
样本数据:
Selection(medical_payments = Limit("one_hundred")).asJson
Run Code Online (Sandbox Code Playgroud)
输出:
{
"medical_payments":
{
"Limit": { "limit_value":"one_hundred" } // additional object added
}
}
Run Code Online (Sandbox Code Playgroud)
同样为Json添加了Selection(medical_payments = Waived(true)).asJson一个附加项Waived:{...}。
我希望它可以是“或”。实现此目标的最佳方法是什么?
我唯一想到的方法(不是我喜欢的)是使用每个文档的forProductN功能并手动完成所有这些操作-但这对于大型Json来说很麻烦。
使用generic-extras中的配置,您几乎可以通过泛型派生完成此操作:
sealed trait LimitOrWaiver
case class Limit(limitValue: String) extends LimitOrWaiver
case class Waived(waived: Boolean) extends LimitOrWaiver
case class Selection(medicalPayments: LimitOrWaiver)
import io.circe.generic.extras.Configuration, io.circe.generic.extras.auto._
import io.circe.syntax._
implicit val codecConfiguration: Configuration =
Configuration.default.withDiscriminator("type").withSnakeCaseMemberNames
Run Code Online (Sandbox Code Playgroud)
然后:
scala> Selection(medicalPayments = Limit("one_hundred")).asJson
res0: io.circe.Json =
{
"medical_payments" : {
"limit_value" : "one_hundred",
"type" : "Limit"
}
}
Run Code Online (Sandbox Code Playgroud)
(请注意,我还将Scala case类的成员名称更改为Scala惯用的驼峰式大小写,并在配置中处理了对蛇形大写的转换。)
这并不是您真正想要的,因为有这个额外的type成员,但是circe的通用派生仅支持可双向往返的编码器/解码器,并且没有某种类型的鉴别器-像这样的成员或您指向的额外对象层解决这个问题—通过JSON来回传递任意ADT的值是不可能的。
这可能很好-您可能不关心type对象中的多余内容。如果您确实在意,您仍然可以使用衍生功能,但需要做一些额外的工作:
import io.circe.generic.extras.Configuration, io.circe.generic.extras.auto._
import io.circe.generic.extras.semiauto._
import io.circe.ObjectEncoder, io.circe.syntax._
implicit val codecConfiguration: Configuration =
Configuration.default.withDiscriminator("type").withSnakeCaseMemberNames
implicit val encodeLimitOrWaiver: ObjectEncoder[LimitOrWaiver] =
deriveEncoder[LimitOrWaiver].mapJsonObject(_.remove("type"))
Run Code Online (Sandbox Code Playgroud)
和:
scala> Selection(medicalPayments = Limit("one_hundred")).asJson
res0: io.circe.Json =
{
"medical_payments" : {
"limit_value" : "one_hundred"
}
}
Run Code Online (Sandbox Code Playgroud)
如果您真的想要,甚至可以使它自动执行,那么type它将从您派生的所有ADT编码器中删除。
| 归档时间: |
|
| 查看次数: |
157 次 |
| 最近记录: |