Chih
Chih

Reputation: 105

Automatic derivation of Enumeration can't find Encoder

I have a case class like this:

case class Admin(name: String, role: Role)

Role is an Enumeration

object Role extends Enumeration {
  type Role = Value
  val Manager = Value
}

When I try to:

import io.circe.generic.auto._, io.circe.syntax._

val response = Admin("John", Role.Manager).asJson.noSpaces

I get the implicit Encoder not found error.

not enough arguments for method asJson: (implicit encoder: io.circe.Encoder[Admin])io.circe.Json. Unspecified value parameter encoder.

I suppose this error is due Enumeration, so I changed to:

trait Role

object Role {
  object Manager extends Role
}

But this does't work too.

Lastly, I tried:

trait Role

object Manager extends Role

And no success. Can someone help me please? Thanks!

Upvotes: 3

Views: 1264

Answers (2)

bfdes
bfdes

Reputation: 101

For anyone coming to this question now, you don't have to use enumeratum, although it is probably your best bet in a large codebase.

As this answer explains, circe supports semi-automatic derivation of enum encoders out of the box.

I found circe -- through circe-generics -- was also able to derive encoders for abstract data types, but the results were surprising:

import io.circe.generic.auto._

sealed trait Role

object Role {
  case object Manager extends Role
  case object IC extends Role
}

Role.Manager.asJson.toString // "{}"

Employee("John", Role.Manager)
  .asJson
  .toString // "{"name": "John", "role": {"Manager": {}}}"

I suspect shapeless, an underlying dependency of circe, treats objects as product types with a zero-parameter list.

It is possible to quickly write an Encoder instance for Role with semi-automatic derivation. Use Encoder[String] to summon an existing encoder, then transform Role into a String:

implicit val encoder: Encoder[Role] = 
  Encoder[String].contramap {
    case Manager => "Manager"
    case IC => "IC"
  }

Upvotes: 0

Mario Galic
Mario Galic

Reputation: 48430

enumeratum-circe enables the following syntax

object CirceEnumeratumExample extends App {
  import enumeratum._
  import io.circe.generic.auto._, io.circe.syntax._

  sealed trait Role extends EnumEntry
  case object Role extends Enum[Role] with CirceEnum[Role] {
    case object Manager  extends Role
    case object User extends Role
    val values = findValues
  }

  case class Admin(name: String, role: Role)
  val response = Admin("John", Role.Manager).asJson.noSpaces
  println(response)
}

which outputs

{"name":"John","role":"Manager"}

where

libraryDependencies += "com.beachape" %% "enumeratum" % "1.5.13",
libraryDependencies += "com.beachape" %% "enumeratum-circe" % "1.5.21"

Upvotes: 2

Related Questions