You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Enumeratum枚举实现Zio-JSON的简单字符串编解码?

问题翻译

我有一个基于Enumeratum的简单枚举:

import enumeratum._

sealed trait Fruit extends EnumEntry

object Fruit extends Enum[Fruit] {
  override val values: IndexedSeq[Fruit] = findValues
  case object Avocado extends Fruit
  case object Banana  extends Fruit
  case object Tomato  extends Fruit
}

我希望使用Zio-JSON将其编码和解码为如下格式的JSON:

someObject: {
  ...
  "fruit": "Banana"
  ...
}

请问实现这一需求的简洁干净的方法是什么?


解决方案

方法一:使用Enumeratum的Zio-JSON集成模块

这是最省心的方式,直接借助官方提供的集成工具生成编解码器。

  1. 添加依赖
    在build.sbt中引入集成模块(请使用对应版本的最新稳定版):
libraryDependencies += "com.beachape" %% "enumeratum-zio-json" % "1.7.2"
  1. 生成编解码器
    在枚举的伴生对象中集成工具类并自动生成JsonCodec:
import enumeratum._
import zio.json._
import enumeratum.zio.json.EnumeratumZioJson

sealed trait Fruit extends EnumEntry

object Fruit extends Enum[Fruit] with EnumeratumZioJson[Fruit] {
  override val values: IndexedSeq[Fruit] = findValues
  
  // 自动推导枚举的Json编解码器
  implicit val fruitCodec: JsonCodec[Fruit] = deriveEnumeratumCodec(this)
  
  case object Avocado extends Fruit
  case object Banana  extends Fruit
  case object Tomato  extends Fruit
}

之后就可以直接在包含Fruit字段的类中使用:

case class SomeObject(fruit: Fruit, otherField: String)

object SomeObject {
  implicit val codec: JsonCodec[SomeObject] = DeriveJsonCodec.gen[SomeObject]
}

// 编码示例
val obj = SomeObject(Fruit.Banana, "demo")
val jsonStr = obj.toJson // 输出: {"fruit":"Banana","otherField":"demo"}

// 解码示例
val decodedResult = """{"fruit":"Banana","otherField":"demo"}""".fromJson[SomeObject]

方法二:手动实现JsonCodec(无需额外依赖)

如果不想引入新依赖,可以手动基于Zio-JSON的transform方法实现编解码逻辑:

import enumeratum._
import zio.json._

sealed trait Fruit extends EnumEntry

object Fruit extends Enum[Fruit] {
  override val values: IndexedSeq[Fruit] = findValues
  
  implicit val fruitCodec: JsonCodec[Fruit] = JsonCodec.string.transform(
    // 编码:将枚举实例转为对应的字符串
    _.value,
    // 解码:根据字符串查找枚举实例,失败则返回错误信息
    str => withNameOption(str).toRight(s"无效的水果类型: $str")
  )
  
  case object Avocado extends Fruit
  case object Banana  extends Fruit
  case object Tomato  extends Fruit
}

可选自定义字符串格式

如果需要将枚举转为非默认名称的字符串(比如小写、蛇形命名),可以让Fruit继承Enumeratum的命名特质:

// 转为小写字符串,比如Banana对应"banana"
sealed trait Fruit extends EnumEntry.Lowercase

// 转为大写下划线格式,比如Banana对应"BANANA"
sealed trait Fruit extends EnumEntry.UpperCase

// 自定义字符串
case object Banana extends Fruit {
  override val value: String = "yellow_fruit"
}

内容的提问来源于stack exchange,提问作者Peter Lamberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 13:42:52