简体   繁体   English

Scala - 解码 JSON 时忽略大小写 class 字段

[英]Scala - Ignore case class field when decoding JSON

I'm playing with the example ADT in the circe documentation to reproduce an issue that I have with JSON decoding.我正在使用 circe 文档中的示例 ADT 来重现我在 JSON 解码时遇到的问题。

To achieve that, I'm using ShapesDerivation:为此,我使用 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

The ADT to decode is composed by two values: a simple case class and another one that I have dedicated Encoder / Decoder (to reproduce in minimal example the issue that I really have):要解码的 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)
    }
  }

Then when I try to decode a simple value like this, it's working well:然后,当我尝试解码这样的简单值时,它运行良好:

scala> import ShapesDerivation._
import ShapesDerivation._

scala> decode[Event](""" { "i" : 10 }""")
res1: Either[io.circe.Error,Event] = Right(Foo(10))

But if I tried to decode something that should be a Bar that contains a Foobar , I get a decoding failure:但是,如果我尝试解码应该是包含FoobarBar的内容,则会出现解码失败:

scala> decode[Event](""" { "x" : 10 }""")
res2: Either[io.circe.Error,Event] = Left(DecodingFailure(CNil, List()))

But this one works because I explicitely put the case class field name:但这一个有效,因为我明确提出了案例 class 字段名称:

scala> decode[Event](""" { "f" : { "x" : 10 }}""")
res7: Either[io.circe.Error,Event] = Right(Bar(FooBar(10)))

I don't what to put the case class field, directly the JSON but I think it's not possible to achieve a such behaviour.我不应该将案例 class 字段直接放在 JSON 中,但我认为不可能实现这样的行为。 The reason why I think it's impossible is how it will know to match the good case class if there is not the field but I want to be sure that there is no way with circe to do that我认为不可能的原因是,如果没有该字段,它将如何知道匹配好案例 class 但我想确定 circe 没有办法做到这一点

Here's how you do it using just semi-auto derivation.以下是仅使用 半自动推导的方法。

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 }"""))
}

Outputs输出

Right(Bar(FooBar(10)))

It gets a bit noisy with the explicit decoders, but if you care about compilation speed, it's the way to go since you'll only derive decoders once.显式解码器会有点吵,但如果你关心编译速度,这是通往 go 的方法,因为你只会派生一次解码器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM