找不到参数编码器的隐式值:io.circe.Encoder[com.sweetsoft.SapHealth]
could not find implicit value for parameter encoder: io.circe.Encoder[com.sweetsoft.SapHealth]
我有以下代码,无法编译:
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
我错过了什么?
特性SapHealth
应该被封印。
您专门 up-cast build
到 SapHealth
,但您没有为 SapHealth
提供 Encoder
实例(仅 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
}
请注意,您还需要重新排列定义以避免 运行 由于初始化顺序而变成 null-pointer 异常(如果您将 create
放在 encodeFieldType
之前,派生SapHealth
编码器将在初始化之前尝试使用 encodeFieldType
)。通过上面的重新排列,效果很好:
scala> SapHealth.create
res2: String = {"SapHealthAccepted":{"sap-id":"foo","requested_at":123}}
请注意,派生的 SapHealth
编码器正在使用您的自定义 SapHealthAccepted
编码器,我认为这就是您想要的。
只是为了 class 你可以使用 deriveEncoder/deriveDecoder。但是在复杂的情况下 class 你应该(我认为)为参数的 classes.
指定它
https://circe.github.io/circe/codecs/semiauto-derivation.html
import io.circe._, io.circe.generic.semiauto._
case class Foo(a: Int, b: String, c: Boolean)
implicit val fooDecoder: Decoder[Foo] = deriveDecoder[Foo]
implicit val fooEncoder: Encoder[Foo] = deriveEncoder[Foo]
我有以下代码,无法编译:
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
我错过了什么?
特性SapHealth
应该被封印。
您专门 up-cast build
到 SapHealth
,但您没有为 SapHealth
提供 Encoder
实例(仅 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
}
请注意,您还需要重新排列定义以避免 运行 由于初始化顺序而变成 null-pointer 异常(如果您将 create
放在 encodeFieldType
之前,派生SapHealth
编码器将在初始化之前尝试使用 encodeFieldType
)。通过上面的重新排列,效果很好:
scala> SapHealth.create
res2: String = {"SapHealthAccepted":{"sap-id":"foo","requested_at":123}}
请注意,派生的 SapHealth
编码器正在使用您的自定义 SapHealthAccepted
编码器,我认为这就是您想要的。
只是为了 class 你可以使用 deriveEncoder/deriveDecoder。但是在复杂的情况下 class 你应该(我认为)为参数的 classes.
指定它https://circe.github.io/circe/codecs/semiauto-derivation.html
import io.circe._, io.circe.generic.semiauto._
case class Foo(a: Int, b: String, c: Boolean)
implicit val fooDecoder: Decoder[Foo] = deriveDecoder[Foo]
implicit val fooEncoder: Encoder[Foo] = deriveEncoder[Foo]