如何用Lombok生成枚举的fromCode方法及AttributeConverter?
解决方案
一、生成fromCode方法的替代方案
Lombok本身没有内置注解可以直接生成枚举的fromCode反向查找方法,但完全不用在每个枚举里复制粘贴循环代码,以下是几种更优雅的实现方式:
1. 预初始化映射Map(高效简洁)
在枚举内部初始化一个code -> 枚举实例的Map,查找效率为O(1),代码量极少:
@AllArgsConstructor @Getter public enum FOO { ALICE("A"), BOB("B"); private final String code; // 预初始化映射Map private static final Map<String, FOO> CODE_TO_ENUM = Arrays.stream(values()) .collect(Collectors.toMap(FOO::getCode, Function.identity())); public static FOO fromCode(String code) { return CODE_TO_ENUM.get(code); } }
注:用@Getter注解自动生成code字段的getter,或者手动编写,否则Lambda表达式无法访问私有字段
2. 通用工具类(复用逻辑)
写一个通用的枚举工具类,把查找逻辑抽离出来,所有枚举共享:
import java.util.function.Function; public class EnumLookupUtils { /** * 根据指定字段反向查找枚举实例 * @param enumClass 枚举类 * @param targetValue 目标字段值 * @param fieldExtractor 字段提取器(从枚举实例中获取要匹配的字段) * @return 匹配的枚举实例,无匹配返回null */ public static <E extends Enum<E>, V> E lookupByField(Class<E> enumClass, V targetValue, Function<E, V> fieldExtractor) { for (E enumInstance : enumClass.getEnumConstants()) { V fieldValue = fieldExtractor.apply(enumInstance); if (targetValue == null ? fieldValue == null : targetValue.equals(fieldValue)) { return enumInstance; } } return null; } }
然后在枚举中只需一行代码调用:
@AllArgsConstructor @Getter public enum FOO { ALICE("A"), BOB("B"); private final String code; public static FOO fromCode(String code) { return EnumLookupUtils.lookupByField(FOO.class, code, FOO::getCode); } }
二、生成JPA AttributeConverter的方案
同样不用手动编写完整的Converter类,通用方案如下:
1. 通用基类Converter
实现一个抽象的基类Converter,所有枚举的Converter只需继承并传入必要参数:
import jakarta.persistence.AttributeConverter; import java.util.function.Function; public abstract class BaseEnumConverter<E extends Enum<E>, C> implements AttributeConverter<E, C> { private final Class<E> enumClass; private final Function<E, C> toDbColumn; private final Function<C, E> toEntity; protected BaseEnumConverter(Class<E> enumClass, Function<E, C> toDbColumn, Function<C, E> toEntity) { this.enumClass = enumClass; this.toDbColumn = toDbColumn; this.toEntity = toEntity; } @Override public C convertToDatabaseColumn(E attribute) { return attribute == null ? null : toDbColumn.apply(attribute); } @Override public E convertToEntityAttribute(C dbData) { return dbData == null ? null : toEntity.apply(dbData); } }
然后你的枚举对应的Converter只需写几行代码:
// 可放在枚举内部,也可单独作为类 public class FooConverter extends BaseEnumConverter<FOO, String> { public FooConverter() { super(FOO.class, FOO::getCode, FOO::fromCode); } }
之后在实体类中直接使用:
@Entity public class SomeEntity { @Convert(converter = FooConverter.class) private FOO foo; // 其他字段... }
2. 自定义注解处理器(进阶方案)
如果想完全实现你说的@MagicEnumConverterAnnotation效果,可以自己编写注解处理器,在编译时自动生成Converter类。不过这个需要一定的注解处理器开发基础,适合需要大量枚举Converter的场景。
内容的提问来源于stack exchange,提问作者Loïc Gammaitoni
相关产品推荐
相关产品推荐

