Reputation: 2506
I'm trying to wrap my head around Circe.
So, here's the model I've been given:
object Gender extends Enumeration {
type Gender = Value
val Male, Female, Unisex, Unknown = Value
}
case class Product(id: String, gender: Gender.Value)
I want to
a) encode the following example as JSON
val product = Product(id = "1234", gender = Gender.Female)
b) map the resulting JSON back onto the Product case class.
My own attempt didn't get me far:
object JsonProtocol {
implicit val productDecoder: Decoder[Product] = deriveDecoder
implicit val productEncoder: Encoder[Product] = deriveEncoder
}
result is a compile time error
Error:(52, 49) could not find Lazy implicit value of type io.circe.generic.decoding.DerivedDecoder[A]
implicit val productDecoder: Decoder[Product] = deriveDecoder
^
I've no idea why this exception is thrown and what the solution could look like. Maybe it's the usage of the Enumeration type?
Upvotes: 16
Views: 13777
Reputation: 14803
For Scala 3 there is now a solution since version 0.14.5 within Circe.
There is a great Blog explaining this: https://scalajobs.com/blog/enum-serialization-in-scala/
The code from the blog:
import io.circe.Codec
import io.circe.derivation.Configuration
given Configuration = Configuration.default
.withDiscriminator("type")
.withTransformConstructorNames(_.toUpperCase)
enum Role {
case Reader(subscription: Subscription)
case Editor(profileBio: String, favoriteFont: String)
case Admin
}
object Role {
given Codec[Role] = Codec.AsObject.derivedConfigured
}
This creates:
{"type":"TESTER","subscription":"GENESIS"}
If you just have simple Enums you can use the following:
import io.circe.derivation.{Configuration, ConfiguredEnumCodec}
given Configuration = Configuration.default
enum TestOverrideType derives ConfiguredEnumCodec:
case Exists, NotExists, IsEquals, HasSize
This creates:
"NotExists"
Thanks for the help of Lasering
My earlier answer:
For Scala 3 there is no solution today within Circe.
However there is a library that works nicely: circe-tagged-adt-codec
Here an example that works for me (the rest I do with semiautomatic derivation from Circe):
enum TestOverrideType derives JsonTaggedAdt.PureEncoder:
case Exists, NotExists, IsEquals, HasSize
Upvotes: 4
Reputation: 14803
The accepted answer is deprecated (circe 0.12.0).
Circe provides now these functions:
Decoder.decodeEnumeration[E <: Enumeration](enum: E)
Encoder.encodeEnumeration[E <: Enumeration](enum: E)
With the example:
implicit val genderDecoder: Decoder[Gender.Value] = Decoder.decodeEnumeration(Gender)
implicit val genderEncoder: Encoder[Gender.Value] = Encoder.encodeEnumeration(Gender)
Upvotes: 15
Reputation: 515
Have a look at enumeratum if you want to use enumerations with circe. You could then try something like this:
import enumeratum._
sealed trait Gender extends EnumEntry
case object Gender extends CirceEnum[Gender] with Enum[Gender] {
case object Male extends Gender
case object Female extends Gender
case object Unisex extends Gender
case object Unknown extends Gender
val values = findValues
}
Gender.values.foreach { gender =>
assert(gender.asJson == Json.fromString(gender.entryName))
}
This should work with circe's automatic derivation for use with your case classes.
Upvotes: 11
Reputation: 171
Try defining your own encoders and decoders for the enum using:
Decoder.enumDecoder[E <: Enumeration](enum: E)
Encoder.enumEncoder[E <: Enumeration](enum: E)
something like:
object JsonProtocol {
implicit val genderDecoder: Decoder[Gender.Value] = Decoder.enumDecoder(Gender)
implicit val genderEncoder: Encoder[Gender.Value] = Encoder.enumEncoder(Gender)
implicit val productDecoder: Decoder[Product] = deriveDecoder
implicit val productEncoder: Encoder[Product] = deriveEncoder
}
These are needed because the automatic/semiautomatic derivers only work for hierarchies of sealed trait
s and case classes
as far as I know. The reason you see that error is because the derived codecs for Product
will implicitly require encoders/decoders for the types of each of it's parameters. An encoder/decoder for String
is a standard part of Circe, but you'll probably need to create ones for your own enumerations.
Upvotes: 15