Обнаружены ошибки при попытке написать либо кодировщик Circe, либо декодер для ADT - PullRequest
2 голосов
/ 14 апреля 2019

Я пытаюсь написать код на основе документации Circe , однако попытка скомпилировать мой кодировщик и декодер приводит к ошибке.

Если вы хотите взглянуть на весь проект, вы можете сделать это на github ( ссылка на файл, с которым у меня возникли проблемы )

Декодер

Попытка скомпилировать следующий код:

package model

import java.time.LocalDateTime

import cats.effect.IO
import cats.syntax.functor._
import io.circe.generic.auto._
import io.circe.syntax._
import io.circe.{Decoder, Encoder}
import org.http4s.EntityDecoder
import org.http4s.circe.jsonOf

package object account {

  sealed trait AccountStatus
  case object Onboarding       extends AccountStatus
  case object SubmissionFailed extends AccountStatus
  case object Submitted        extends AccountStatus
  case object AccountUpdated   extends AccountStatus
  case object ApprovalPending  extends AccountStatus
  case object Active           extends AccountStatus
  case object Rejected         extends AccountStatus

  object AccountStatus {

    implicit val accountStatusEncoder: Encoder[AccountStatus] = Encoder.instance {
      case onboarding@Onboarding => onboarding.asJson
      case submissionFailed@SubmissionFailed => submissionFailed.asJson
      case submitted@Submitted => submitted.asJson
      case accountUpdated@AccountUpdated => accountUpdated.asJson
      case approvalPending@ApprovalPending => approvalPending.asJson
      case active@Active => active.asJson
      case rejected@Rejected => rejected.asJson
    }

    implicit val accountStatusDecoder: Decoder[AccountStatus] =
      List[Decoder[AccountStatus]](
        Decoder[Onboarding].widen,
        Decoder[SubmissionFailed].widen,
        Decoder[Submitted].widen,
        Decoder[AccountUpdated].widen,
        Decoder[ApprovalPending].widen,
        Decoder[Active].widen,
        Decoder[Rejected].widen
      ).reduceLeft(_ or _)

    implicit val AccountStatusEntityDecoder = jsonOf[IO, AccountStatus]

  }


  case class Account(
                      id: String,
                      status: AccountStatus,
                      currency: String,
                      buyingPower: Double,
                      cash: Double,
                      cashWithdrawable: Double,
                      portfolioValue: Double,
                      patternDayTrader: Boolean,
                      tradingBlocked: Boolean,
                      transfersBlocked: Boolean,
                      accountBlocked: Boolean,
                      createdAt: LocalDateTime
                    )

  object Account {
    implicit val AccountDecoder: EntityDecoder[IO, Account] = jsonOf[IO, Account]
  }

}

приводит к следующим ошибкам:

[error] /home/tom/code/scalpaca/src/main/scala/model/account.scala:38:19: not found: type Onboarding
[error]           Decoder[Onboarding].widen,
[error]                   ^
[error] /home/tom/code/scalpaca/src/main/scala/model/account.scala:39:19: not found: type SubmissionFailed
[error]           Decoder[SubmissionFailed].widen,
[error]                   ^
[error] /home/tom/code/scalpaca/src/main/scala/model/account.scala:40:19: not found: type Submitted
[error]           Decoder[Submitted].widen,
[error]                   ^
[error] /home/tom/code/scalpaca/src/main/scala/model/account.scala:41:19: not found: type AccountUpdated
[error]           Decoder[AccountUpdated].widen,
[error]                   ^
[error] /home/tom/code/scalpaca/src/main/scala/model/account.scala:42:19: not found: type ApprovalPending
[error]           Decoder[ApprovalPending].widen,
[error]                   ^
[error] /home/tom/code/scalpaca/src/main/scala/model/account.scala:43:19: not found: type Active
[error]           Decoder[Active].widen,
[error]                   ^
[error] /home/tom/code/scalpaca/src/main/scala/model/account.scala:44:19: not found: type Rejected
[error]           Decoder[Rejected].widen
[error]                   ^
[error] 7 errors found

Я нахожу это довольно запутанным, поскольку типы, на которые жалуется компилятор, достаточно четко видны, по крайней мере, насколько я могу судить.

Кодер

Сняв декодер, AccountStatusEntityDecoder, который зависит от него, и поле AccountStatus из учетной записи, оставив ниже

package model

import java.time.LocalDateTime

import cats.effect.IO
import cats.syntax.functor._
import io.circe.generic.auto._
import io.circe.syntax._
import io.circe.{Decoder, Encoder}
import org.http4s.EntityDecoder
import org.http4s.circe.jsonOf

package object account {

  sealed trait AccountStatus
  case object Onboarding       extends AccountStatus
  case object SubmissionFailed extends AccountStatus
  case object Submitted        extends AccountStatus
  case object AccountUpdated   extends AccountStatus
  case object ApprovalPending  extends AccountStatus
  case object Active           extends AccountStatus
  case object Rejected         extends AccountStatus

  object AccountStatus {

    implicit val accountStatusEncoder: Encoder[AccountStatus] = Encoder.instance {
      case onboarding@Onboarding => onboarding.asJson
      case submissionFailed@SubmissionFailed => submissionFailed.asJson
      case submitted@Submitted => submitted.asJson
      case accountUpdated@AccountUpdated => accountUpdated.asJson
      case approvalPending@ApprovalPending => approvalPending.asJson
      case active@Active => active.asJson
      case rejected@Rejected => rejected.asJson
    }

  }

  case class Account(
                      id: String,
                      currency: String,
                      buyingPower: Double,
                      cash: Double,
                      cashWithdrawable: Double,
                      portfolioValue: Double,
                      patternDayTrader: Boolean,
                      tradingBlocked: Boolean,
                      transfersBlocked: Boolean,
                      accountBlocked: Boolean,
                      createdAt: LocalDateTime
                    )

  object Account {
    implicit val AccountDecoder: EntityDecoder[IO, Account] = jsonOf[IO, Account]
  }

}

Я снова получаю некоторые предупреждения и ошибки:

[info] Compiling 1 Scala source to /home/tom/code/scalpaca/target/scala-2.12/classes ...
[warn] /home/tom/code/scalpaca/src/main/scala/model/account.scala:27:48: match may not be exhaustive.
[warn] It would fail on the following input: Onboarding
[warn]       case onboarding@Onboarding => onboarding.asJson
[warn]                                                ^
[warn] /home/tom/code/scalpaca/src/main/scala/model/account.scala:28:66: match may not be exhaustive.
[warn] It would fail on the following input: SubmissionFailed
[warn]       case submissionFailed@SubmissionFailed => submissionFailed.asJson
[warn]                                                                  ^
[warn] /home/tom/code/scalpaca/src/main/scala/model/account.scala:29:45: match may not be exhaustive.
[warn] It would fail on the following input: Submitted
[warn]       case submitted@Submitted => submitted.asJson
[warn]                                             ^
[warn] /home/tom/code/scalpaca/src/main/scala/model/account.scala:30:60: match may not be exhaustive.
[warn] It would fail on the following input: AccountUpdated
[warn]       case accountUpdated@AccountUpdated => accountUpdated.asJson
[warn]                                                            ^
[warn] /home/tom/code/scalpaca/src/main/scala/model/account.scala:31:63: match may not be exhaustive.
[warn] It would fail on the following input: ApprovalPending
[warn]       case approvalPending@ApprovalPending => approvalPending.asJson
[warn]                                                               ^
[warn] /home/tom/code/scalpaca/src/main/scala/model/account.scala:32:36: match may not be exhaustive.
[warn] It would fail on the following input: Active
[warn]       case active@Active => active.asJson
[warn]                                    ^
[warn] /home/tom/code/scalpaca/src/main/scala/model/account.scala:33:42: match may not be exhaustive.
[warn] It would fail on the following input: Rejected
[warn]       case rejected@Rejected => rejected.asJson
[warn]                                          ^
[error] Error while emitting account.scala
[error] assertion failed: 
[error]   Cannot emit primitive conversion from Lmodel/account/package$AccountStatus; to Lmodel/account/package$Onboarding$; - account.scala
[error]      while compiling: /home/tom/code/scalpaca/src/main/scala/model/account.scala
[error]         during phase: jvm
[error]      library version: version 2.12.8
[error]     compiler version: version 2.12.8
[error]   reconstructed args: -bootclasspath /home/tom/jdk1.8.0_201/jre/lib/resources.jar:/home/tom/jdk1.8.0_201/jre/lib/rt.jar:/home/tom/jdk1.8.0_201/jre/lib/sunrsasign.jar:/home/tom/jdk1.8.0_201/jre/lib/jsse.jar:/home/tom/jdk1.8.0_201/jre/lib/jce.jar:/home/tom/jdk1.8.0_201/jre/lib/charsets.jar:/home/tom/jdk1.8.0_201/jre/lib/jfr.jar:/home/tom/jdk1.8.0_201/jre/classes:/home/tom/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.12.8.jar -Ypartial-unification -classpath /home/tom/code/scalpaca/target/scala-2.12/classes:/home/tom/.ivy2/cache/io.circe/circe-generic_2.12/jars/circe-generic_2.12-0.11.1.jar:/home/tom/.ivy2/cache/io.circe/circe-parser_2.12/jars/circe-parser_2.12-0.11.1.jar:/home/tom/.ivy2/cache/io.circe/circe-java8_2.12/jars/circe-java8_2.12-0.11.1.jar:/home/tom/.ivy2/cache/org.http4s/http4s-circe_2.12/jars/http4s-circe_2.12-0.20.0-M4.jar:/home/tom/.ivy2/cache/org.http4s/http4s-dsl_2.12/jars/http4s-dsl_2.12-0.20.0-M4.jar:/home/tom/.ivy2/cache/org.http4s/http4s-blaze-client_2.12/jars/http4s-blaze-client_2.12-0.20.0-M4.jar:/home/tom/.ivy2/cache/com.chuusai/shapeless_2.12/bundles/shapeless_2.12-2.3.3.jar:/home/tom/.ivy2/cache/io.circe/circe-jawn_2.12/jars/circe-jawn_2.12-0.11.1.jar:/home/tom/.ivy2/cache/org.http4s/http4s-jawn_2.12/jars/http4s-jawn_2.12-0.20.0-M4.jar:/home/tom/.ivy2/cache/org.http4s/http4s-client_2.12/jars/http4s-client_2.12-0.20.0-M4.jar:/home/tom/.ivy2/cache/org.http4s/http4s-blaze-core_2.12/jars/http4s-blaze-core_2.12-0.20.0-M4.jar:/home/tom/.ivy2/cache/io.circe/circe-core_2.12/jars/circe-core_2.12-0.11.1.jar:/home/tom/.ivy2/cache/org.typelevel/macro-compat_2.12/jars/macro-compat_2.12-1.1.1.jar:/home/tom/.ivy2/cache/org.typelevel/jawn-parser_2.12/jars/jawn-parser_2.12-0.14.1.jar:/home/tom/.ivy2/cache/org.http4s/jawn-fs2_2.12/jars/jawn-fs2_2.12-0.13.0.jar:/home/tom/.ivy2/cache/org.http4s/http4s-core_2.12/jars/http4s-core_2.12-0.20.0-M4.jar:/home/tom/.ivy2/cache/org.http4s/blaze-http_2.12/jars/blaze-http_2.12-0.14.0-M11.jar:/home/tom/.ivy2/cache/io.circe/circe-numbers_2.12/jars/circe-numbers_2.12-0.11.1.jar:/home/tom/.ivy2/cache/org.spire-math/jawn-parser_2.12/jars/jawn-parser_2.12-0.13.0.jar:/home/tom/.ivy2/cache/org.http4s/parboiled_2.12/jars/parboiled_2.12-1.0.0.jar:/home/tom/.ivy2/cache/co.fs2/fs2-io_2.12/jars/fs2-io_2.12-1.0.2.jar:/home/tom/.ivy2/cache/org.eclipse.jetty.alpn/alpn-api/jars/alpn-api-1.1.3.v20160715.jar:/home/tom/.ivy2/cache/com.twitter/hpack/jars/hpack-1.0.2.jar:/home/tom/.ivy2/cache/org.http4s/blaze-core_2.12/jars/blaze-core_2.12-0.14.0-M11.jar:/home/tom/.ivy2/cache/org.log4s/log4s_2.12/jars/log4s_2.12-1.6.1.jar:/home/tom/.ivy2/cache/co.fs2/fs2-core_2.12/jars/fs2-core_2.12-1.0.2.jar:/home/tom/.ivy2/cache/org.typelevel/cats-effect_2.12/jars/cats-effect_2.12-1.1.0.jar:/home/tom/.ivy2/cache/org.slf4j/slf4j-api/jars/slf4j-api-1.7.25.jar:/home/tom/.ivy2/cache/org.scodec/scodec-bits_2.12/jars/scodec-bits_2.12-1.1.7.jar:/home/tom/.ivy2/cache/org.typelevel/cats-core_2.12/jars/cats-core_2.12-1.5.0.jar:/home/tom/.ivy2/cache/org.typelevel/cats-kernel_2.12/jars/cats-kernel_2.12-1.5.0.jar:/home/tom/.ivy2/cache/org.typelevel/cats-macros_2.12/jars/cats-macros_2.12-1.5.0.jar:/home/tom/.ivy2/cache/org.typelevel/machinist_2.12/jars/machinist_2.12-0.6.6.jar:/home/tom/.ivy2/cache/org.scala-lang/scala-reflect/jars/scala-reflect-2.12.6.jar
[error] 
[error]   last tree to typer: TypeTree(trait Decoder)
[error]        tree position: line 53 of /home/tom/code/scalpaca/src/main/scala/model/account.scala
[error]             tree tpe: io.circe.Decoder
[error]               symbol: abstract trait Decoder in package circe
[error]    symbol definition: abstract trait Decoder extends Serializable (a ClassSymbol)
[error]       symbol package: io.circe
[error]        symbol owners: trait Decoder
[error]            call site: constructor package$Account$anon$importedDecoder$macro$28$1$anon$macro$25$1 in package account
[error] 
[error] == Source file context for tree position ==
[error] 
[error]     50                     )
[error]     51 
[error]     52   object Account {
[error]     53     implicit val AccountDecoder: EntityDecoder[IO, Account] = jsonOf[IO, Account]
[error]     54   }
[error]     55 
[error]     56 }
[error] Error while emitting account.scala
[error] assertion failed: Cannot emit primitive conversion from Lmodel/account/package$AccountStatus; to Lmodel/account/package$SubmissionFailed$; - account.scala
[error] Error while emitting account.scala
[error] assertion failed: Cannot emit primitive conversion from Lmodel/account/package$AccountStatus; to Lmodel/account/package$Submitted$; - account.scala
[error] Error while emitting account.scala
[error] assertion failed: Cannot emit primitive conversion from Lmodel/account/package$AccountStatus; to Lmodel/account/package$AccountUpdated$; - account.scala
[error] Error while emitting account.scala
[error] assertion failed: Cannot emit primitive conversion from Lmodel/account/package$AccountStatus; to Lmodel/account/package$ApprovalPending$; - account.scala
[error] Error while emitting account.scala
[error] assertion failed: Cannot emit primitive conversion from Lmodel/account/package$AccountStatus; to Lmodel/account/package$Active$; - account.scala
[error] Error while emitting account.scala
[error] assertion failed: Cannot emit primitive conversion from Lmodel/account/package$AccountStatus; to Lmodel/account/package$Rejected$; - account.scala
[warn] 7 warnings found
[error] 7 errors found

Я не могу понять, почему аккаунт затронут. Если я полностью удаляю сопутствующий объект AccountStatus, мой проект компилируется.

Мне нужна помощь в устранении этих ошибок, ваш вклад все равно будет принят. Спасибо

1 Ответ

2 голосов
/ 14 апреля 2019

Чтобы дать полный ответ тем, кто может наткнуться на этот вопрос позже:

Предложение stsatlantis действительно решает одну из проблем (спасибо за ваш комментарий!), В то время как другую можно решить, слегка изменив accountStatusEncoder. Альтернативное решение состоит в том, чтобы использовать case-классы в вашей ADT, однако, если у вас уже есть case-объекты, это возможно потому, что они лучше соответствуют вашим потребностям / домену.

Изменения, с которыми я закончил:

  object AccountStatus {

  implicit val accountStatusEncoder: Encoder[AccountStatus] =
    Encoder.instance {
      status => status match {
          case Onboarding => status.asJson
          case SubmissionFailed => status.asJson
          case Submitted => status.asJson
          case AccountUpdated => status.asJson
          case ApprovalPending => status.asJson
          case Active => status.asJson
          case Rejected => status.asJson
      }
    }

  implicit val accountStatusDecoder: Decoder[AccountStatus] =
    List[Decoder[AccountStatus]](
      Decoder[Onboarding.type].widen,
      Decoder[SubmissionFailed.type].widen,
      Decoder[Submitted.type].widen,
      Decoder[AccountUpdated.type].widen,
      Decoder[ApprovalPending.type].widen,
      Decoder[Active.type].widen,
      Decoder[Rejected.type].widen
    ).reduceLeft(_ or _)

  implicit val AccountStatusEntityDecoder = jsonOf[IO, AccountStatus]
}
...