не удалось найти неявное значение для кодировщика параметров: io.circe.Encoder [com.sweetsoft.SapHealth] - PullRequest
3 голосов
/ 30 мая 2019

У меня есть следующий код, который не компилируется:

import java.time.Instant

import io.circe.{Decoder, Encoder}
import io.circe.generic.auto._
import io.circe.syntax._

trait SapHealth {}

case class SapHealthRejected(reason: String) extends SapHealth

case class SapHealthAccepted(sapId: String, requestedAt: Long) extends SapHealth


object SapHealth {

  private val build: SapHealth = SapHealthAccepted(SapmockActor.system.name, Instant.now().getEpochSecond)

  val create: String = build.asJson.noSpaces

  implicit val encodeFieldType: Encoder[SapHealthAccepted] =
    Encoder.forProduct2("sap-id", "requested_at")(SapHealthAccepted.unapply(_).get)

  implicit val decodeFieldType: Decoder[SapHealthAccepted] =
    Decoder.forProduct2("sap-id", "requested_at")(SapHealthAccepted.apply)

}

Компилятор жалуется:

could not find implicit value for parameter encoder: io.circe.Encoder[com.sweetsoft.SapHealth]
[error]   val create: String = build.asJson.noSpaces

Чего мне не хватает?

Ответы [ 2 ]

4 голосов
/ 30 мая 2019

Вы специально повышали build до SapHealth, но вы не предоставляете экземпляр Encoder для SapHealth (только SapHealthAccepted), и circe-generic не может получить его, потому чтовы не запечатали иерархию признаков.

Наиболее простым решением было бы добавить sealed:

import io.circe.{Decoder, Encoder}
import io.circe.generic.auto._
import io.circe.syntax._

sealed trait SapHealth {}
case class SapHealthRejected(reason: String) extends SapHealth
case class SapHealthAccepted(sapId: String, requestedAt: Long) extends SapHealth

object SapHealth {
  implicit val encodeFieldType: Encoder[SapHealthAccepted] =
    Encoder.forProduct2("sap-id", "requested_at")(SapHealthAccepted.unapply(_).get)

  implicit val decodeFieldType: Decoder[SapHealthAccepted] =
    Decoder.forProduct2("sap-id", "requested_at")(SapHealthAccepted.apply)

  private val build: SapHealth = SapHealthAccepted("foo", 123L)

  val create: String = build.asJson.noSpaces
}

Обратите внимание, что вам также необходимо изменить определения, чтобы избежать появления нулевого значения-исключение указателя из-за порядка инициализации (если вы поставите create перед encodeFieldType, производный кодер SapHealth попытается использовать encodeFieldType до его инициализации).С приведенной выше перестановкой это работает просто отлично:

scala> SapHealth.create
res2: String = {"SapHealthAccepted":{"sap-id":"foo","requested_at":123}}

Обратите внимание, что производный SapHealth кодировщик использует ваш пользовательский SapHealthAccepted кодировщик, который, как я полагаю, вам нужен.

1 голос
/ 30 мая 2019

Черта SapHealth должна быть запечатана.

...