为什么它不解码为ADT类型



我试图将以下字符串得出适当的ADT类型:

res6: String = {"raw":"Hello","status":{"MsgSuccess":{}}} 

使用CIRCE库。

ADT类型看起来如下:

sealed trait MsgDoc {
}
final case class MsgPreFailure(raw: String, reasons: Chain[String]) extends MsgDoc
final case class MsgProceed(raw: String, status: MsgStatus) extends MsgDoc

MsgStatus类型:

sealed trait MsgStatus {
}
case object MsgSuccess extends MsgStatus
final case class MsgFailure(reasons: Chain[String]) extends MsgStatus
final case class MsgUnknown(reason: String) extends MsgStatus

,我尝试开车:

object MsgDocDerivation {
  import shapeless.{Coproduct, Generic}
  implicit def encodeAdtNoDiscr[A, Repr <: Coproduct](implicit
                                                      gen: Generic.Aux[A, Repr],
                                                      encodeRepr: Encoder[Repr]
                                                     ): Encoder[A] = encodeRepr.contramap(gen.to)
  implicit def decodeAdtNoDiscr[A, Repr <: Coproduct](implicit
                                                      gen: Generic.Aux[A, Repr],
                                                      decodeRepr: Decoder[Repr]
                                                     ): Decoder[A] = decodeRepr.map(gen.from)
}

和执行:

object Main extends App {

  val json = MsgProceed("Hello", MsgSuccess).asJson
  println(json)
  val adt = decode[MsgDoc](json.noSpaces)
  println(adt)
} 

结果我得到了:

{
  "raw" : "Hello",
  "status" : {
    "MsgSuccess" : {
    }
  }
}
Left(DecodingFailure(CNil, List())) 

如您所见,它不能正确 decode

可以找到源代码https://gitlab.com/playscala/adtjson。

我不太确定MsgDocDerivation的内容要做什么 - 似乎不必要和分散注意力 - 但我认为关键问题是Circe的编码(和解码(是由静态驱动的类型,而不是编码(或解码(值的运行时类。这意味着以下两个JSON值将有所不同:

val value = MsgProceed("Hello", MsgSuccess)
val json1 = value.asJson
val json2 = (value: MsgDoc).asJson

在您的情况下,以下对我有用:

import cats.data.Chain
sealed trait MsgStatus
case object MsgSuccess extends MsgStatus
final case class MsgFailure(reasons: Chain[String]) extends MsgStatus
final case class MsgUnknown(reason: String) extends MsgStatus
sealed trait MsgDoc
final case class MsgPreFailure(raw: String, reasons: Chain[String]) extends MsgDoc
final case class MsgProceed(raw: String, status: MsgStatus) extends MsgDoc
import io.circe.generic.auto._, io.circe.jawn.decode, io.circe.syntax._
val value: MsgDoc = MsgProceed("Hello", MsgSuccess)
val json = value.asJson
val backToValue = decode[MsgDoc](json.noSpaces)

请注意,json与您所看到的不同:

scala> json
res0: io.circe.Json =
{
  "MsgProceed" : {
    "raw" : "Hello",
    "status" : {
      "MsgSuccess" : {
      }
    }
  }
}
scala> backToValue
res1: Either[io.circe.Error,MsgDoc] = Right(MsgProceed(Hello,MsgSuccess))

这是因为我已经执行了(TypesAfe(从MsgProceedMsgDoc的(TypeAfe(。无论如何,这通常是您与ADT合作的方式 - 您不是在静态键入案例类子类型的情况下,而是作为sealed trait基本类型。

事实是,MsgProceedMsgProceed类型和类型MsgDoc一样,编码为不同的JSON。因此,您尝试从错误的JSON解码MsgDoc

  val json = MsgProceed("Hello", MsgSuccess).asJson
  println(json)
  //{
  //  "raw" : "Hello",
  //  "status" : {
  //    "MsgSuccess" : {
  //
  //    }
  //  }
  //}
  val json1 = (MsgProceed("Hello", MsgSuccess): MsgDoc).asJson
  println(json1)
  //{
  //  "MsgProceed" : {
  //    "raw" : "Hello",
  //    "status" : {
  //      "MsgSuccess" : {
  //
  //      }
  //    }
  //  }
  //}
  val adt0 = decode[MsgProceed](json.noSpaces)
  println(adt0)
  //Right(MsgProceed(Hello,MsgSuccess))
  val adt1 = decode[MsgDoc](json1.noSpaces)
  println(adt1)
  //Right(MsgProceed(Hello,MsgSuccess))
  val adt = decode[MsgDoc](json.noSpaces)
  println(adt)
  //Left(DecodingFailure(CNil, List()))

最新更新