gpt4 book ai didi

scala - 如何让 circe 为生成的 Json 提供非此即彼的输出方案?

转载 作者:行者123 更新时间:2023-12-01 07:16:32 25 4
gpt4 key购买 nike

这就是我的意图 - 假设我有一个名为 medical_payments 的字段 - 它可以“要么”是一个限制,如果有人选择或放弃

{
"medical_payments":
{
"limit_value":"one_hundred"
}
}

如果它被选为豁免,那么它应该是:

{
"medical_payments":
{
"waived":true
}
}

到目前为止,这是我所拥有的:

sealed trait LimitOrWaiver
case class Limit(limit_key: String) extends LimitOrWaiver
case class Waived(waived: Boolean) extends LimitOrWaiver

case class Selection(medical_payments: LimitOrWaiver)

示例数据:

Selection(medical_payments = Limit("one_hundred")).asJson

输出:

{
"medical_payments":
{
"Limit": { "limit_value":"one_hundred" } // additional object added
}
}

Selection(medical_payments = Waived(true)).asJson 类似,将额外的 Waived:{...} 添加到 Json。

我希望它是非此即彼。实现这一目标的最佳方法是什么?

我能想到的(不是我喜欢的)唯一方法是使用forProductN 函数per the doc并手动完成所有这些 - 但对于大型 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

然后:

scala> Selection(medicalPayments = Limit("one_hundred")).asJson
res0: io.circe.Json =
{
"medical_payments" : {
"limit_value" : "one_hundred",
"type" : "Limit"
}
}

(请注意,我还将 Scala 案例类成员名称更改为 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"))

和:

scala> Selection(medicalPayments = Limit("one_hundred")).asJson
res0: io.circe.Json =
{
"medical_payments" : {
"limit_value" : "one_hundred"
}
}

如果您真的想要,您甚至可以将其设为自动,这样 type 就会从您派生的任何 ADT 编码器中删除。

关于scala - 如何让 circe 为生成的 Json 提供非此即彼的输出方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55961842/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com