Когда я тестировал ваш код с несколькими изменениями (убрал несколько вещей, чтобы упростить компиляцию кода):
type StatusCode = Int
sealed trait ValuationResponse {
def statusCode: StatusCode
}
case class SuccessfulResponse(succ: String, statusCode: StatusCode) extends ValuationResponse
case class FailingResponse(reason: String, statusCode: StatusCode) extends ValuationResponse
case class ValuationRequest(test: String)
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 _)
}
val caseObject = FailingResponse("Some Error", 200)
val jsonString = caseObject
.asJson
.printWith(Printer.noSpaces)
Я получил
@ decode[ValuationResponse](jsonString)
res21: Either[Error, ValuationResponse] = Left(DecodingFailure(CNil, List()))
Однако, когда я импортировал импликации из object
@ import derivation._
import derivation._
@ decode[ValuationResponse](jsonString)
res23: Either[Error, ValuationResponse] = Right(FailingResponse("Some Error", 200))
По умолчанию Circe использует поле дискриминации для различения guish между членами типа суммы. Вы можете увидеть, во что закодировано ваше значение, если вы не импортируете derivation
объект:
@ {
val jsonString = (caseObject : ValuationResponse)
.asJson
.printWith(Printer.noSpaces)
}
jsonString: String = "{\"FailingResponse\":{\"reason\":\"Some Error\",\"statusCode\":200}}"
Итак, вы использовали автоматически производные кодеки, когда декодировали свой класс case - если вы удалили import io.circe.generic.auto._
ваш компиляция потерпит неудачу, когда вы попытаетесь декодировать вещи без импорта кодов, которые вы сами написали (import derivation._
).
Чтобы избежать таких ситуаций в будущем:
- не импортировать
io.circe.generic.auto._
на производстве на сайте использования кодеков - это позволяет получить новый код c для класса дел, который должен использовать ваш рукописный / полученный вручную код c (что приводит к ошибкам, подобным этому) - предпочитают
io.circe.generic.semiauto._
вызывать производные кодеки там, где они вам нужны (вместо Decoder[A]
write deriveDecoder[A]
) - помещайте ваши полуавтоматически производные кодеки, а также рукописные кодеки в сопутствующие объекты типов, для которых вы получаете кодеки (если это возможно) - это избавит от необходимости импортировать их вручную каждый раз, когда они вам понадобятся
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 _)
}
Кстати. использование semiauto также помогает вам избежать других ошибок, таких как cycli c -зависимость от инициализации вашего неявного в вашем коде:
@ derivation.decodeRequest.decodeJson("test".asJson)
java.lang.NullPointerException
ammonite.$sess.cmd7$.<clinit>(cmd7.sc:1)
, но если он использовал deriveDecoder
:
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))))