Repository navigation
[Enhancement] Allow @ExcelProperty on custom annotations #915
Description
Activity
bengbengbalabalabeng commented
on May 13, 2026 ContributorMore actionsHi, @ergehenmeng
To better understand the limitations you are currently facing, could you provide a simplified code example (including your current annotation usage, converter, etc.) that illustrates your current approach and the specific issues you’re encountering?
It will be much easier for us to discuss possible improvement directions :)
bengbengbalabalabeng commented
on May 20, 2026 ContributorMore actionsFor the convenience of subsequent discussion, I have broken this requirement down into several more specific sub-issues to avoid mixing too many topics in a single Issue.
sub-issues:
- Add composable annotations support
- Add
AnnotationAttributesAwareConverterinterface implements custom composable annotation attributes callbacks. (Not yet)
谢谢回复,
目前我实现枚举类型的转换是通过 注解+转换器实现的 例子如下:
@Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelDesc { } @Slf4j public class EnumExcelConverter implements Converter<Object> { private static final Map<Class<?>, Field> FIELD_MAP = new ConcurrentHashMap<>(32); @Override public Class<?> supportJavaTypeKey() { return Enum.class; } @Override public WriteCellData<?> convertToExcelData(Object value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { Field valueAs = this.getAnnotationField(contentProperty); return new WriteCellData<>(ReflectUtil.getFieldValue(value, valueAs).toString()); } /** * 获取带有@ExcelDesc注解的属性 * * @param contentProperty 原导出excel的字段 * @return Field */ private Field getAnnotationField(ExcelContentProperty contentProperty) { Class<?> fieldType = contentProperty.getField().getType(); return FIELD_MAP.computeIfAbsent(fieldType, aClass -> { for (Field field : contentProperty.getField().getType().getDeclaredFields()) { ExcelDesc excelDesc = field.getAnnotation(ExcelDesc.class); if (excelDesc != null) { return field; } } log.error("枚举类请使用@ExcelDesc标注要导出为Excel的字段 [{}]", fieldType); throw new BusinessException(ErrorCode.ENUM_SUPPORTED); }); } } @Getter @AllArgsConstructor public enum Gender { /** * 未知 */ NONE(0, "未知"), /** * 男 */ MALE(1, "男"), /** * 女 */ FEMALE(2, "女"); @JsonValue @EnumValue private final int value; @ExcelDesc private final String name; @JsonCreator(mode = JsonCreator.Mode.DELEGATING) public static Gender of(@JsonProperty("value") Integer value) { if (value == null) { return null; } return Arrays.stream(Gender.values()).filter(auditState -> auditState.value == value) .findFirst().orElseThrow(() -> new BusinessException(ErrorCode.USER_TYPE_NULL)); } } // 使用时 是这样的 @Schema(description = "性别 0:未知 1:男 2:女 ") @ExcelProperty(value = "性别", index = 6, converter = EnumExcelConverter.class) private Gender sex;
数据字典翻译类型的例子如下:
@Slf4j public class DictConverter implements Converter<Integer> { @Override public Class<?> supportJavaTypeKey() { return Integer.class; } @Override public WriteCellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { ExcelDict dict = contentProperty.getField().getAnnotation(ExcelDict.class); if (dict == null) { return NumberUtils.formatToCellDataString(value, contentProperty); } SysDictService service = SpringUtil.getBean(SysDictService.class); String dictValue = service.getDictValue(dict.value(), value); if (dictValue == null) { log.warn("导出Excel解析数据字典为空 [{}] [{}]", dict.value(), value); return NumberUtils.formatToCellDataString(value, contentProperty); } return new WriteCellData<>(dictValue); } } @Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExcelDict { /** * 数据字典的key * * @return key */ String value(); } // 使用时 @Schema(description = "反馈类型 数据字典: dict_feed_type") @ExcelDict(value = "dict_feed_type") @ExcelProperty(value = "反馈类型", index = 3, converter = DictConverter .class) private Integer feedType;
上述两种方式太过于繁琐, 且不够优雅, 我理想的方式是通过 实现自定义注解+自定义转换器, 把上面枚举+数据字典都能兼容即用 DictExcelProperty 注解代替 ExcelProperty注解
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented @ExcelProperty(converter = DictConverter.class) public @interface DictExcelProperty { /** * 导出时在Excel中显示的列名 */ String value() default ""; /** * 字典类型,对应sys_dict_data表的dict_type字段 * 例如:sys_user_sex, sys_job_status等 */ String dictType(); /** * 本地数据字典转换 1=是,0=否 */ String translate() default ""; @AliasFor(annotation = ExcelProperty.class, index= "value") int index() default -1; @AliasFor(annotation = ExcelProperty.class, index= "order") int order() default Integer.MAX_VALUE; }
Reacted by Bengbengbalabalabeng and Lance@ergehenmeng @bengbengbalabalabeng
你们好,我也在解决这个问题,并发起了讨论,我觉得不使用注解,直接使用枚举,像mybatis-plus一样,枚举实现一个具体的接口,那个这个枚举的字段就可以直接用来导入导出。这样使用起来更简单。
#1005@ergehenmeng @bengbengbalabalabeng 你们好,我也在解决这个问题,并发起了讨论,我觉得不使用注解,直接使用枚举,像mybatis-plus一样,枚举实现一个具体的接口,那个这个枚举的字段就可以直接用来导入导出。这样使用起来更简单。 #1005
我看了你的这个实现, 通过枚举确实能实现翻译, 但是太过于耦合, 如果放开 DictExcelProperty 注解权限, 自由度会更高,
@CustomDictExcelProperty(translate="1=是,0=否", dictType="sex")
你可以通过这种自定义注解实现更多可能, 不限于枚举, 对于简单的可以解析字符串格式, 也能解析数据字典, 翻译来源就没有什么限制了, 如果单纯为了枚举, 上面我定义的转换器实际上和你的差不多, 你的是实现IEnum 我是通过@ExcelDesc注解你好,使用枚举的前提是,这些类型的值都是提前确定好了的,如果是使用注解,也是提前硬编码到注解中,而且对于用惯了EasyExcel的@ExcelProperty的开发者有一些心理负担,虽然使用注解也可以,那这样的话,所有需要翻译的字段都需要加上这个注解(或者拓展@ExcelProperty)。最后我觉得实现起来的复杂度和需要校验的成本会比较大。
使用枚举是因为业务代码中会直接使用这个枚举。业务开发者会像操作基本数据类型的包装类一样直接使用他。直接像mybatis-plus一样实现一个IEnum接口,就无需做其他配置了
#issuecomment-5261830229
#198
这里两个问题都是为了解决这个问题的讨论。我们可以在#988 这里进行统一讨论。你好,使用枚举的前提是,这些类型的值都是提前确定好了的,如果是使用注解,也是提前硬编码到注解中,而且对于用惯了EasyExcel的@ExcelProperty的开发者有一些心理负担,虽然使用注解也可以,那这样的话,所有需要翻译的字段都需要加上这个注解(或者拓展@ExcelProperty)。最后我觉得实现起来的复杂度和需要校验的成本会比较大。
使用枚举是因为业务代码中会直接使用这个枚举。业务开发者会像操作基本数据类型的包装类一样直接使用他。直接像mybatis-plus一样实现一个IEnum接口,就无需做其他配置了 #issuecomment-5261830229 #198 这里两个问题都是为了解决这个问题的讨论。我们可以在#988 这里进行统一讨论。
实际上只要开放注解, 你可以单独使用自定义注解, 从而忽略掉原生注解, 可以在一个注解上实现, 自定义翻译 数据库数据字典翻译 或者枚举翻译 , 甚至更多可能性, 你可以自己定义自己的枚举接口定义在这个注解内, 而且从实现的技术单独角度来说很简单, 也符合高内聚低耦合的理念
我理解你的意思了,但是开放注解是怎么开放呢?就是提供注解的解析器?不管使用什么注解,最终的读或者写都需要转换器去做。
如果针对字段,需要去数据库查的话。目前的版本自定义转换器就可以实现了。类似于JsonProperty 这种复合式注解
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @JacksonAnnotationsInside @JsonSerialize(using = SensitiveJsonSerializer.class) public @interface Sensitive { DesensitizedType desensitizedType(); }
只需要一个转换器就可以实现同一类型转换, 直接使用注解即可, 不需要每个字段都定义转换器, 相当于对
ExcelProperty注解做了增强, 在保持原有功能,还能额外支持自己定制化的需求, 目前ExcelProperty不支持符合注解哦哦。相当于放类上嘛,在读或者写的时候,可以统一注册自定义的转换器啊
AbstractParameterBuilder#registerConverter哦哦。相当于放类上嘛,在读或者写的时候,可以统一注册自定义的转换器啊
AbstractParameterBuilder#registerConverter是的, 代码会更简洁, 扩展性更强, 具体实现全靠使用者自己, 甚至可以定义一些自己的二级转换器实现更通用的扩展
你可以尝试实现你的想法,然后提pr嘛
- changed the title
[-][Enhancement] @ExcelProperty 开放注解范围[/-][+][Enhancement] Allow @ExcelProperty on custom annotations[/+]on Oct 5, 2026
Search before asking
Motivation
目前ExcelPropery只能使用在Field, 导致如果字段是status这种, 只能手动增加转换器, 各类型不一样 就要增加很多转换器或者通过组合注解实现(太臃肿了), 希望开放ExcelPropery可以放在注解类上, 实现自定义注解, 用来翻译数据字典, 类似这样
Solution
No response
Alternatives
No response
Anything else?
No response
Are you willing to submit a PR?