I am trying to find a simple and efficient way to (de)serialize enums in Scala 3 using circe
.
Consider the following example:
import io.circe.generic.auto._
import io.circe.syntax._
enum OrderType:
case BUY
case SELL
case class Order(id: Int, `type`: OrderType, amount: String)
val order = Order(1, OrderType.SELL, "123.4")
order.asJson
On serializing the data, it becomes
{
"id" : 1,
"type" : {
"SELL" : {
}
},
"amount" : "123.4"
}
instead of
{
"id" : 1,
"type" : "SELL",
"amount" : "123.4"
}
which is what I want.
I know that I can write a custom (de)serializer for this which will solve the issue for this particular instance like this:
implicit val encodeOrderType: Encoder[OrderType] = (a: OrderType) =>
Encoder.encodeString(a.toString)
implicit def decodeOrderType: Decoder[OrderType] = (c: HCursor) => for {
v <- c.as[String]
} yield OrderType.valueOf(v)
but I was looking for a generic solution that might work for any enum
.
EDIT 1
One way of doing serialization, (deserialization does not work :/) is to make all enums extend a common trait and define encoder for all enums extending it. For the above example, it looks something like this.
trait EnumSerialization
enum OrderType extends EnumSerialization:
case BUY
case SELL
enum MagicType extends EnumSerialization:
case FIRE
case WATER
case EARTH
case WIND
implicit def encodeOrderType[A <: EnumSerialization]: Encoder[A] = (a: A) => Encoder.encodeString(a.toString)
// This correctly serializes all instances of enum into a string
case class Order(id: Int, `type`: OrderType, amount: String)
val order = Order(1, OrderType.SELL, "123.4")
val orderJson = order.asJson
// Serializes to { "id" : 1, "type" : "SELL", "amount" : "123.4"}
case class Magic(id: Int, magic: MagicType)
val magic = Magic(3, MagicType.WIND)
val magicJson = magic.asJson
// Serializes to { "id" : 3, "magic" : "WIND"}
However this does not extend to deserialization.