Circe 和 Scala 的枚举类型

Circe and Scala's Enumeration type

我正在努力思考 Circe。

所以,这是我得到的模型:

object Gender extends Enumeration {
     type Gender = Value
     val Male, Female, Unisex, Unknown = Value
}

case class Product(id: String, gender: Gender.Value)

我要

a) 将这个简单示例编码为 JSON 字符串

        val product = Product(id = "1234", gender = Gender.Female)

b) 将结果 JSON 映射回产品案例 class.


我自己的尝试并没有让我走得太远:

  object JsonProtocol {
      implicit val productDecoder: Decoder[Product] = deriveDecoder
      implicit val productEncoder: Encoder[Product] = deriveEncoder
  }

导致编译时错误

   Error:(52, 49) could not find Lazy implicit value of type io.circe.generic.decoding.DerivedDecoder[A]
   implicit val productDecoder: Decoder[Product] = deriveDecoder
                                            ^

我不知道为什么会抛出这个异常,也不知道解决方案是什么样的。也许是枚举类型的用法?但是,我只是猜测。

尝试使用以下方法为枚举定义您自己的编码器和解码器:

Decoder.enumDecoder[E <: Enumeration](enum: E)
Encoder.enumEncoder[E <: Enumeration](enum: E)

类似于:

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
}

这些是必需的,因为据我所知,automatic/semiautomatic 派生程序仅适用于 sealed traitcase classes 的层次结构。您看到该错误的原因是因为 Product 的派生编解码器将隐式要求 encoders/decoders 每个参数的类型。 String 的 encoder/decoder 是 Circe 的标准部分,但您可能需要为自己的枚举创建一个。

如果您想在 circe 中使用枚举,请查看 enumeratum。然后你可以尝试这样的事情:

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))
}

这应该与 circe 的自动推导一起用于您的案例 类。

接受的答案已弃用(大约 0.12.0)。

Circe 现在提供这些功能:

Decoder.decodeEnumeration[E <: Enumeration](enum: E)
Encoder.encodeEnumeration[E <: Enumeration](enum: E)

以例:

implicit val genderDecoder: Decoder[Gender.Value] = Decoder.decodeEnumeration(Gender)
implicit val genderEncoder: Encoder[Gender.Value] = Encoder.encodeEnumeration(Gender)