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

如何在Avro4s中将IntEnum字段转换为整数类型

问题描述

在Scala中使用Avro4s序列化样例类时,希望将IntEnum类型的字段在Avro Schema中以整数类型(而非Avro枚举类型)表示。

当前样例类代码:

@AvroName("MyCaseClass")
case class MyCaseClass(detectedDeliveryType: DeliveryType, ...)

object DeliveryType extends IntEnum[DeliveryType] {
  case object Unknown extends DeliveryType(0)
  case object Desktop extends DeliveryType(1)
  case object MobileWeb extends DeliveryType(2)
  case object MobileApp extends DeliveryType(3)
  case object CTV extends DeliveryType(4)

  override val values: IndexedSeq[DeliveryType] = findValues
}

Avro4s默认生成的Schema:

{
  "name": "detectedDeliveryType",
  "type": {
    "type": "enum",
    "name": "DeliveryType",
    "namespace": "mypackage.enums",
    "symbols": [
      "CTV",
      "Desktop",
      "MobileApp",
      "MobileWeb",
      "Unknown"
    ]
  }
}

期望生成的Schema:

{
  "name": "detectedDeliveryType",
  "type": "int"
}
解决方案

Avro4s基于类型类机制处理Schema生成与序列化/反序列化,只需为IntEnum类型自定义SchemaFor和Codec实例即可实现需求。

方法1:为单个枚举类型定义实例

在DeliveryType的伴生对象中添加以下隐式实例,确保作用域内可用:

import com.sksamuel.avro4s._
import org.apache.avro.Schema

object DeliveryType extends IntEnum[DeliveryType] {
  case object Unknown extends DeliveryType(0)
  case object Desktop extends DeliveryType(1)
  case object MobileWeb extends DeliveryType(2)
  case object MobileApp extends DeliveryType(3)
  case object CTV extends DeliveryType(4)

  override val values: IndexedSeq[DeliveryType] = findValues

  // 自定义Schema生成逻辑,将DeliveryType映射为Avro int类型
  implicit val schemaFor: SchemaFor[DeliveryType] = SchemaFor.int

  // 自定义序列化/反编解码器
  implicit val codec: Codec[DeliveryType] = new Codec[DeliveryType] {
    override def schema: Schema = schemaFor.schema
    // 序列化:将枚举转为对应的整数值
    override def encode(value: DeliveryType): AnyRef = Int.box(value.value)
    // 反序列化:根据整数查找对应的枚举实例
    override def decode(value: Any): DeliveryType = DeliveryType.withValue(value.asInstanceOf[Int])
  }
}

方法2:通用化处理所有IntEnum类型

如果项目中有多个IntEnum类型需要统一处理为Avro int,可以定义通用的隐式实例,无需为每个枚举重复编写代码:

import com.sksamuel.avro4s._
import enumeratum.{IntEnum, IntEnumEntry}
import org.apache.avro.Schema

// 通用Schema生成逻辑:所有IntEnumEntry子类映射为Avro int
implicit def intEnumSchemaFor[E <: IntEnumEntry]: SchemaFor[E] = SchemaFor.int

// 通用编解码器:处理所有IntEnum类型的序列化与反序列化
implicit def intEnumCodec[E <: IntEnumEntry](implicit enum: IntEnum[E]): Codec[E] = new Codec[E] {
  override def schema: Schema = SchemaFor.int.schema
  override def encode(value: E): AnyRef = Int.box(value.value)
  override def decode(value: Any): E = enum.withValue(value.asInstanceOf[Int])
}

验证效果

当生成MyCaseClass的Avro Schema时,detectedDeliveryType字段将被生成为int类型,符合预期。

注意事项

  • 确保上述隐式实例在生成Schema、执行序列化/反序列化的代码作用域内可见。
  • 反序列化时,若输入的整数不存在于枚举定义中,withValue会抛出NoSuchElementException,如需容错处理,可改用withValueOpt并添加错误逻辑。

内容的提问来源于stack exchange,提问作者Zvi Mints

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 05:25:29