如何为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集成模块
这是最省心的方式,直接借助官方提供的集成工具生成编解码器。
- 添加依赖
在build.sbt中引入集成模块(请使用对应版本的最新稳定版):
libraryDependencies += "com.beachape" %% "enumeratum-zio-json" % "1.7.2"
- 生成编解码器
在枚举的伴生对象中集成工具类并自动生成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
相关产品推荐
相关产品推荐

