如何避免为枚举转Short/Int编写多个AttributeConverter?
通用枚举转Short的AttributeConverter实现方案
问题背景
目前通过编写AttributeConverter实现枚举与Short类型的数据库持久化转换,但已有约10个重复的转换器实现,代码冗余严重。同时因枚举顺序变更会引发数据异常,不考虑使用@Enumerated(EnumType.ORDINAL)方案。
通用解决方案
1. 定义枚举通用接口
创建一个统一接口,让所有需要转换的枚举类实现它,规范值的获取与转换逻辑:
interface ShortValuedEnum { val value: Short companion object { inline fun <reified T : ShortValuedEnum> fromValue(value: Short): T { return enumValues<T>().firstOrNull { it.value == value } ?: throw IllegalArgumentException("Invalid value: $value for enum ${T::class.simpleName}") } } }
2. 实现通用转换器
编写泛型版AttributeConverter,基于上述接口实现通用的双向转换逻辑:
@Converter(autoApply = true) class ShortEnumConverter<E : Enum<E> & ShortValuedEnum> : AttributeConverter<E, Short> { override fun convertToDatabaseColumn(attribute: E?): Short? { return attribute?.value } override fun convertToEntityAttribute(dbData: Short?): E? { return dbData?.let { ShortValuedEnum.fromValue(it) } } }
注:设置
autoApply = true后,所有实现ShortValuedEnum的枚举会自动应用该转换器,无需在实体类中单独声明@Convert;若需个别例外,可单独指定转换器覆盖全局配置。
3. 修改现有枚举类
让你的枚举实现ShortValuedEnum接口,移除原重复的转换方法:
enum class MyEnum(override val value: Short) : ShortValuedEnum { RED(0), GREEN(1); }
4. 实体类使用示例
现在实体类无需指定特定转换器,直接声明枚举类型即可:
@Entity @Table(name = "my_table") class MyEntity( @Id val id: Long, @Column(name = "status", nullable = false) val color: MyEnum )
若不需要全局自动应用,也可手动指定通用转换器:
@Convert(converter = ShortEnumConverter::class) @Column(name = "status", nullable = false) val color: MyEnum
方案优势
- 彻底消除重复的转换器代码,所有符合规范的枚举可复用同一转换器
- 规避
EnumType.ORDINAL的顺序依赖风险,基于枚举固定value字段转换 - 支持全局自动应用或手动指定两种模式,适配不同业务场景
内容的提问来源于stack exchange,提问作者KotlinOverflow
相关产品推荐
相关产品推荐

