Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

could not find implicit value for parameter encoder: io.circe.Encoder[com.sweetsoft.SapHealth]

Tags:

scala

circe

I have the following code, that does not compile:

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)

}

The compiler complains:

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

What am I missing?

like image 354
softshipper Avatar asked Oct 18 '25 22:10

softshipper


1 Answers

You've specifically up-cast build to SapHealth, but you don't provide an Encoder instance for SapHealth (only SapHealthAccepted), and circe-generic can't derive one because you haven't sealed the trait hierarchy.

The most straightforward solution would be to add 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
}

Note that you also need to rearrange the definitions to avoid running into null-pointer exceptions because of initialization order (if you put create before encodeFieldType, the derived SapHealth encoder will try to use encodeFieldType before it's initialized). With the rearrangement above, this works just fine:

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

Note that the derived SapHealth encoder is using your custom SapHealthAccepted encoder, which I assume is what you want.

like image 199
Travis Brown Avatar answered Oct 20 '25 16:10

Travis Brown



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!