如何使用 circe 将密封的 trait case 对象转换为字符串

Kay*_*Kay 14 scala circe

我正在使用 Scala 和 Circe。我有以下密封特征。

  sealed trait Mode
  case object Authentication extends Mode
  case object Ocr extends Mode
Run Code Online (Sandbox Code Playgroud)

调用此 case 对象时的输出SessionModel.Authentication如下:

"Authentication":{}
Run Code Online (Sandbox Code Playgroud)

我需要将其转换为字符串以便输出 "authentication"

Tra*_*own 14

正如 Andriy Plokhotnyuk 上面提到的,你可以使用 circe-generic-extras:

import io.circe.Codec
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto.deriveEnumerationCodec

sealed trait Mode
case object Authentication extends Mode
case object Ocr extends Mode

object Mode {
  private implicit val config: Configuration =
    Configuration.default.copy(transformConstructorNames = _.toLowerCase)

  implicit val modeCodec: Codec[Mode] = deriveEnumerationCodec[Mode]
}
Run Code Online (Sandbox Code Playgroud)

进而:

scala> import io.circe.syntax._
import io.circe.syntax._

scala> (Authentication: Mode).asJson
res1: io.circe.Json = "authentication"

scala> io.circe.Decoder[Mode].decodeJson(res1)
res2: io.circe.Decoder.Result[Mode] = Right(Authentication)
Run Code Online (Sandbox Code Playgroud)

(请注意,这Codec是 0.12 中的新功能 - 对于早期版本,您必须按照 Andriy 的评论写出两个实例。)

除非你有很多这些需要维护,但我个人认为手工编写实例通常比使用 circe-generic-extras 更好,在这种情况下它甚至不会更冗长:

import io.circe.{Decoder, Encoder}

sealed trait Mode
case object Authentication extends Mode
case object Ocr extends Mode

object Mode {
  implicit val decodeMode: Decoder[Mode] = Decoder[String].emap {
    case "authentication" => Right(Authentication)
    case "ocr"            => Right(Ocr)
    case other            => Left(s"Invalid mode: $other")
  }

  implicit val encodeMode: Encoder[Mode] = Encoder[String].contramap {
    case Authentication => "authentication"
    case Ocr            => "ocr"
  }
}
Run Code Online (Sandbox Code Playgroud)

它的工作原理与deriveEnumerationCodec版本完全相同,但除了 circe-core 之外不需要任何东西,不那么神奇,编译速度更快,等等。泛型派生对于具有直接映射的简单案例类非常有用,但我认为人们经常尝试当手动编写实例时,将其拉伸以涵盖所有情况不会造成太大负担,甚至可能更清晰。