Scala - 解码 JSON 时忽略大小写 class 字段
Scala - Ignore case class field when decoding JSON
我正在使用 circe 文档中的示例 ADT 来重现我在 JSON 解码时遇到的问题。
为此,我正在使用 ShapesDerivation :
scala> object ShapesDerivation {
|
| implicit def encodeAdtNoDiscr[Event, Repr <: Coproduct](implicit
| gen: Generic.Aux[Event, Repr],
| encodeRepr: Encoder[Repr]
| ): Encoder[Event] = encodeRepr.contramap(gen.to)
|
| implicit def decodeAdtNoDiscr[Event, Repr <: Coproduct](implicit
| gen: Generic.Aux[Event, Repr],
| decodeRepr: Decoder[Repr]
| ): Decoder[Event] = decodeRepr.map(gen.from)
|
| }
defined object ShapesDerivation
要解码的 ADT 由两个值组成:一个简单的案例 class 和另一个我专用的编码器/解码器(以最小的示例重现我真正遇到的问题):
scala> :paste
// Entering paste mode (ctrl-D to finish)
sealed trait Event
object Event {
case class Foo(i: Int) extends Event
case class Bar(f : FooBar) extends Event
case class FooBar(x : Int)
implicit val encoderFooBar : Encoder[FooBar] = new Encoder[FooBar] {
override def apply(a: FooBar): Json = Json.obj(("x", Json.fromInt(a.x)))
}
implicit val decodeFooBar: Decoder[FooBar] = new Decoder[FooBar] {
override def apply(c: HCursor): Result[FooBar] =
for {
x <- c.downField("x").as[Int]
} yield FooBar(x)
}
}
然后当我尝试像这样解码一个简单的值时,它运行良好:
scala> import ShapesDerivation._
import ShapesDerivation._
scala> decode[Event](""" { "i" : 10 }""")
res1: Either[io.circe.Error,Event] = Right(Foo(10))
但是如果我尝试解码应该是 Bar
且包含 Foobar
的内容,我会遇到解码失败:
scala> decode[Event](""" { "x" : 10 }""")
res2: Either[io.circe.Error,Event] = Left(DecodingFailure(CNil, List()))
但是这个有效,因为我明确地输入了大小写 class 字段名称:
scala> decode[Event](""" { "f" : { "x" : 10 }}""")
res7: Either[io.circe.Error,Event] = Right(Bar(FooBar(10)))
我不知道如何将大小写 class 字段直接放在 JSON 中,但我认为不可能实现这样的行为。我认为这是不可能的原因是如果没有该字段,它将如何知道匹配好的案例 class 但我想确保 circe 无法做到这一点
以下是仅使用 semi-auto 推导的方法。
import io.circe.Decoder.Result
import io.circe.{Decoder, Encoder, HCursor, Json}
import io.circe.parser._
import io.circe.generic.semiauto._
object Example extends App {
sealed trait Event
object Event {
case class Foo(i: Int) extends Event
object Foo {
implicit val decoder: Decoder[Foo] = deriveDecoder
}
case class Bar(f: FooBar) extends Event
object Bar {
implicit val decoder: Decoder[Bar] = Decoder[FooBar].map(Bar.apply)
}
implicit val decoder: Decoder[Event] = Decoder[Foo].widen.or(Decoder[Bar].widen)
}
case class FooBar(x: Int)
object FooBar {
implicit val encoderFooBar: Encoder[FooBar] = deriveEncoder
implicit val decodeFooBar: Decoder[FooBar] = deriveDecoder
}
println(decode[Event](""" { "x" : 10 }"""))
}
产出
Right(Bar(FooBar(10)))
使用显式解码器会有点嘈杂,但如果您关心编译速度,这是可行的方法,因为您只会派生一次解码器。
我正在使用 circe 文档中的示例 ADT 来重现我在 JSON 解码时遇到的问题。
为此,我正在使用 ShapesDerivation :
scala> object ShapesDerivation {
|
| implicit def encodeAdtNoDiscr[Event, Repr <: Coproduct](implicit
| gen: Generic.Aux[Event, Repr],
| encodeRepr: Encoder[Repr]
| ): Encoder[Event] = encodeRepr.contramap(gen.to)
|
| implicit def decodeAdtNoDiscr[Event, Repr <: Coproduct](implicit
| gen: Generic.Aux[Event, Repr],
| decodeRepr: Decoder[Repr]
| ): Decoder[Event] = decodeRepr.map(gen.from)
|
| }
defined object ShapesDerivation
要解码的 ADT 由两个值组成:一个简单的案例 class 和另一个我专用的编码器/解码器(以最小的示例重现我真正遇到的问题):
scala> :paste
// Entering paste mode (ctrl-D to finish)
sealed trait Event
object Event {
case class Foo(i: Int) extends Event
case class Bar(f : FooBar) extends Event
case class FooBar(x : Int)
implicit val encoderFooBar : Encoder[FooBar] = new Encoder[FooBar] {
override def apply(a: FooBar): Json = Json.obj(("x", Json.fromInt(a.x)))
}
implicit val decodeFooBar: Decoder[FooBar] = new Decoder[FooBar] {
override def apply(c: HCursor): Result[FooBar] =
for {
x <- c.downField("x").as[Int]
} yield FooBar(x)
}
}
然后当我尝试像这样解码一个简单的值时,它运行良好:
scala> import ShapesDerivation._
import ShapesDerivation._
scala> decode[Event](""" { "i" : 10 }""")
res1: Either[io.circe.Error,Event] = Right(Foo(10))
但是如果我尝试解码应该是 Bar
且包含 Foobar
的内容,我会遇到解码失败:
scala> decode[Event](""" { "x" : 10 }""")
res2: Either[io.circe.Error,Event] = Left(DecodingFailure(CNil, List()))
但是这个有效,因为我明确地输入了大小写 class 字段名称:
scala> decode[Event](""" { "f" : { "x" : 10 }}""")
res7: Either[io.circe.Error,Event] = Right(Bar(FooBar(10)))
我不知道如何将大小写 class 字段直接放在 JSON 中,但我认为不可能实现这样的行为。我认为这是不可能的原因是如果没有该字段,它将如何知道匹配好的案例 class 但我想确保 circe 无法做到这一点
以下是仅使用 semi-auto 推导的方法。
import io.circe.Decoder.Result
import io.circe.{Decoder, Encoder, HCursor, Json}
import io.circe.parser._
import io.circe.generic.semiauto._
object Example extends App {
sealed trait Event
object Event {
case class Foo(i: Int) extends Event
object Foo {
implicit val decoder: Decoder[Foo] = deriveDecoder
}
case class Bar(f: FooBar) extends Event
object Bar {
implicit val decoder: Decoder[Bar] = Decoder[FooBar].map(Bar.apply)
}
implicit val decoder: Decoder[Event] = Decoder[Foo].widen.or(Decoder[Bar].widen)
}
case class FooBar(x: Int)
object FooBar {
implicit val encoderFooBar: Encoder[FooBar] = deriveEncoder
implicit val decodeFooBar: Decoder[FooBar] = deriveDecoder
}
println(decode[Event](""" { "x" : 10 }"""))
}
产出
Right(Bar(FooBar(10)))
使用显式解码器会有点嘈杂,但如果您关心编译速度,这是可行的方法,因为您只会派生一次解码器。