gpt4 book ai didi

scala - 通过鉴别器使用嵌套的 Coproduct 解码 Case 类

转载 作者:行者123 更新时间:2023-12-01 04:29:09 24 4
gpt4 key购买 nike

我有以下设置

case class A(eventType : String, fieldOne : Int)
case class B(eventType : String, fieldOne : Int, fieldTwo : Int)

type Event = A :+: B :+: CNil

case class X(id :String, events : List[Event])

我收到以下 Json 消息,一个带有一个事件的 X(B 的实例)
{
"id" : "id",
"events" : [
{
"eventType" : "B",
"fieldOne": 1,
"fieldTwo" : 2
}
]
}

如果我使用 circe,我可以将其解码为 X 的实例,但是在事件列表中,因为 A 首先到达副产品,它将解码为 A。
val actual = X("id", [A("B", 1)])
val expected = X("id", [B("B", 1, 2)])

我希望能够使用 eventType 作为配置鉴别器来确定嵌套字段成为 Coproduct 中的哪种类型。

我想答案就在这里

Generic derivation for ADTs in Scala with a custom representation

但我似乎不能完全解决我的情况。

最佳答案

最直接的方法是修改 A 的派生解码器。和 B以便它们在 eventType 时失败不是正确的值。这将导致 coproduct 解码器自然地找到合适的情况:

import shapeless._
import io.circe.Decoder, io.circe.syntax._
import io.circe.generic.semiauto.deriveDecoder
import io.circe.generic.auto._, io.circe.shapes._

case class A(eventType: String, fieldOne: Int)
case class B(eventType: String, fieldOne: Int, fieldTwo: Int)

type Event = A :+: B :+: CNil

case class X(id: String, events: List[Event])

implicit val decodeA: Decoder[A] = deriveDecoder[A].emap {
case a @ A("A", _) => Right(a)
case _ => Left("Invalid eventType")
}

implicit val decodeB: Decoder[B] = deriveDecoder[B].emap {
case b @ B("B", _, _) => Right(b)
case _ => Left("Invalid eventType")
}

val doc = """{
"id" : "id",
"events" : [
{
"eventType" : "B",
"fieldOne": 1,
"fieldTwo" : 2
}
]
}"""

进而:
scala> io.circe.jawn.decode[X](doc)
res0: Either[io.circe.Error,X] = Right(X(id,List(Inr(Inl(B(B,1,2))))))

请注意,您仍然可以使用自动派生的编码器——您只需要在解码端进行额外检查。 (这当然是假设您确保不构造具有无效事件类型的 AB 值,但由于您询问使用该成员作为鉴别器,这似乎没问题。)

更新:如果你不想枚举解码器,你可以这样做:
import io.circe.generic.decoding.DerivedDecoder

def checkType[A <: Product { def eventType: String }](a: A): Either[String, A] =
if (a.productPrefix == a.eventType) Right(a) else Left("Invalid eventType")

implicit def decodeSomeX[A <: Product { def eventType: String }](implicit
decoder: DerivedDecoder[A]
): Decoder[A] = decoder.emap(checkType)

...它应该与上面的代码完全相同。结构类型的东西有很小(几乎可以忽略不计)的运行时成本,但它是完全安全的,在我看来是对这些类型进行抽象的合理方法。

关于scala - 通过鉴别器使用嵌套的 Coproduct 解码 Case 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55635913/

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