Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Json Can';在Scala中使用Circe解码子类_Json_Scala_Enums_Traits_Circe - Fatal编程技术网

Json Can';在Scala中使用Circe解码子类

Json Can';在Scala中使用Circe解码子类,json,scala,enums,traits,circe,Json,Scala,Enums,Traits,Circe,我有一个Scala项目,其中我使用Circe处理json。 我在将JSON解码为层次结构的子类时遇到困难 我遇到问题的代码是以下测试: test("FailingResponse - Conversion between case object and Json works") { val caseObject = FailingResponse("Some Error", StatusCodes.INTERNAL_ERROR) val jsonString = caseOb

我有一个Scala项目,其中我使用Circe处理json。 我在将JSON解码为层次结构的子类时遇到困难

我遇到问题的代码是以下测试:

  test("FailingResponse - Conversion between case object and Json works") {
    val caseObject = FailingResponse("Some Error", StatusCodes.INTERNAL_ERROR)
    val jsonString = caseObject
      .asJson
      .printWith(Printer.noSpaces)

    decode[ValuationResponse](jsonString) must be(Right(caseObject))
  }
我希望能够解码到ValuationResponse的任何子类,因为在解码时,我无法确定响应是失败响应还是成功响应。我希望解码器能够归纳出它是什么类型的评估响应,对它进行解码,并将其作为“通用”评估响应提供。然后,我可以用一个匹配的案例或类似的东西来处理它,以获得实际的特定类型。

相反,我在那个测试中得到的是一个解码失败错误。我做错了什么

这是层次结构的代码:

sealed trait ValuationResponse {
  def statusCode: StatusCode
}

case class SuccessfulResponse(values: List[StockValuation], symbol: String, function: TimeSeriesType, statusCode: StatusCode) extends ValuationResponse

case class FailingResponse(reason: String, statusCode: StatusCode) extends ValuationResponse

case class ValuationRequest(function: TimeSeriesType = TIME_SERIES_INTRADAY, symbol: String, interval: IntraDayInterval = IntraDayIntervals.MIN_5)

object derivation {

  implicit val encodeResponse: Encoder[ValuationResponse] = Encoder.instance {
    case response@SuccessfulResponse(_, _, _, _) => response.asJson
    case response@FailingResponse(_, _) => response.asJson
  }
  implicit val decodeResponse: Decoder[ValuationResponse] =
    List[Decoder[ValuationResponse]](
      Decoder[SuccessfulResponse].widen,
      Decoder[FailingResponse].widen
    ).reduceLeft(_ or _)

  implicit val encodeRequest: Encoder[ValuationRequest] = Encoder.instance {
    case response@ValuationRequest(_, _, _) => response.asJson
  }
  implicit val decodeRequest: Decoder[ValuationRequest] =
    List[Decoder[ValuationRequest]](
      Decoder[ValuationRequest].widen
    ).reduceLeft(_ or _)
}
这些是它使用的枚举(是的,我知道为状态代码使用枚举是愚蠢的啊哈):


当我对您的代码进行了一些修改(删除了一些东西以使代码编译更容易)后:

我得到

但是,当我从对象导入隐式时

@ import derivation._
import derivation._

@ decode[ValuationResponse](jsonString)
res23: Either[Error, ValuationResponse] = Right(FailingResponse("Some Error", 200))
问题是,默认情况下,Circe使用discrimination字段来区分sum类型的成员。如果不导入
派生
对象,则可以查看值的编码格式:

@ {
  val jsonString = (caseObject : ValuationResponse)
        .asJson
        .printWith(Printer.noSpaces)
  }
jsonString: String = "{\"FailingResponse\":{\"reason\":\"Some Error\",\"statusCode\":200}}"
因此,在解码案例类时,您使用了自动派生的编解码器-如果您删除了
import io.circe.generic.auto.\u
,那么当您尝试在不导入自己编写的代码的情况下解码时,您的编译将失败(
import derivation.\u

为避免将来出现此类情况:

  • 不要在编解码器使用站点上的生产上导入
    io.circe.generic.auto.\u
    -这样可以为应该使用手写/手动导出编解码器的案例类派生新的编解码器(这会导致像这样的错误)
  • 首选
    io.circe.generic.semiauto.\u
    在需要的地方调用派生的编解码器(而不是
    Decoder[A]
    write
    deriveDecoder[A]
  • 将半自动派生的编解码器以及手写的编解码器放在派生编解码器类型的伴生对象中(如果可能的话)-这将消除每次需要时手动导入它们的需要
顺便说一句,使用semiauto还可以帮助您避免其他错误,如代码中的错误:

@ derivation.decodeRequest.decodeJson("test".asJson)
java.lang.NullPointerException
  ammonite.$sess.cmd7$.<clinit>(cmd7.sc:1)
你会得到:

@ val decodeRequests: Decoder[ValuationRequest] =
      List[Decoder[ValuationRequest]](
        io.circe.generic.semiauto.deriveDecoder[ValuationRequest].widen
      ).reduceLeft(_ or _)
decodeRequests: Decoder[ValuationRequest] = io.circe.generic.decoding.DerivedDecoder$$anon$1@30570f04

@ decodeRequests.decodeJson("test".asJson)
res9: Decoder.Result[ValuationRequest] = Left(DecodingFailure(Attempt to decode value on failed cursor, List(DownField(test))))

好吧,在做了你建议的那些修改之后,解码工作就开始了。但在编码时,我得到:异常或错误导致运行中止。eventbus.ValuationRequest$.$anonfun$encodeRequest$1(eventBusCases.scala:36)第36行为:caseresponse@ValuationRequest(,,)=>response.asj问题现已解决。我不得不将赋值请求更改为:object ValuationRequest{implicit val encodeRequest:Encoder[ValuationRequest]=deriveEncoder[ValuationRequest]implicit val decodequest:Decoder[ValuationRequest]=deriveDecoder[ValuationRequest]}asJson的递归性显然带来了麻烦。
@ {
  val jsonString = (caseObject : ValuationResponse)
        .asJson
        .printWith(Printer.noSpaces)
  }
jsonString: String = "{\"FailingResponse\":{\"reason\":\"Some Error\",\"statusCode\":200}}"
  import io.circe.generic.semiauto._

  sealed trait ValuationResponse ...
  object ValuationResponse {
    implicit val decodeResponse: Decoder[ValuationResponse] =
      List[Decoder[ValuationResponse]](
        deriveDecoder[SuccessfulResponse].widen,
        deriveDecoder[FailingResponse].widen
      ).reduceLeft(_ or _)
  }
@ derivation.decodeRequest.decodeJson("test".asJson)
java.lang.NullPointerException
  ammonite.$sess.cmd7$.<clinit>(cmd7.sc:1)
implicit val decodeRequest: Decoder[ValuationRequest] =
    List[Decoder[ValuationRequest]](
      deriveDecoder[ValuationRequest].widen
    ).reduceLeft(_ or _)
@ val decodeRequests: Decoder[ValuationRequest] =
      List[Decoder[ValuationRequest]](
        io.circe.generic.semiauto.deriveDecoder[ValuationRequest].widen
      ).reduceLeft(_ or _)
decodeRequests: Decoder[ValuationRequest] = io.circe.generic.decoding.DerivedDecoder$$anon$1@30570f04

@ decodeRequests.decodeJson("test".asJson)
res9: Decoder.Result[ValuationRequest] = Left(DecodingFailure(Attempt to decode value on failed cursor, List(DownField(test))))