Skip to content

[Enhancement] Support annotation-based dictionary conversion #198

Description

@LewisBai97

非常需要这个功能,之前都是自定义处理器来着

Activity

  1. nkuprins commented on Aug 3, 2026

    @nkuprins
    Contributor

    Hi @psxjoy, I have been thinking about this for the last week and have put together a concrete design for it. Please, read it carefully or pin someone who can read it :)

    Proposal: @DictFormat for code-label mapping

    This issue is labelled planning and has no design written down yet, so here is a concrete proposal to react to. I would rather agree on the shape here than open a PR that guesses it.

    TL;DR

    • Problem: a field stores a code (1), the sheet should show a label (Success). Today that needs a hand-written Converter class per dictionary.
    • Proposal: an annotation - @DictFormat({"1=Success", "0=Failure"}) - plus an enum-backed form for dictionaries that already exist in the domain model.
    • Scope: read and write, String / Integer / Long / Short / Byte / Boolean / BigInteger; an unmapped() policy for partial dictionaries.

    Proposed API

    public @interface DictFormat {
        String[] value() default {};                            // "code=label" entries
        Class<? extends Dict> type() default Dict.None.class;   // or an enum implementing Dict
        UnmappedEnum unmapped() default UnmappedEnum.THROW;     // THROW | NULL | PASS_THROUGH
    }

    Inline form, for a mapping used in one place:

    @ExcelProperty("Status")
    @DictFormat({"1=Success", "0=Failure"})
    private Integer status;

    Enum-backed form, for a dictionary that already exists:

    public enum Status implements Dict {
        SUCCESS("1", "Success"),
        FAILURE("0", "Failure");
        // code() and label()
    }
    
    @ExcelProperty("Status")
    @DictFormat(type = Status.class)
    private Integer status;

    Dict would be a two-method interface (code(), label()) that users implement.

    Proposed behaviour

    Field types. Codes would be written as strings in the annotation and converted to the field type, by reusing the registered <Type>StringConverter rather than any new logic.

    I would propose an allowlist rather than "any type with a registered converter", because the types left out fail silently rather than loudly.

    Partial dictionaries. The annotation replaces the converter body, so it has to decide what happens to a value the dictionary does not cover. I would make that an explicit choice rather than pick one behaviour for everybody:

    Policy Write Read
    THROW (proposed default) fail, naming the value fail, naming the label
    NULL empty cell null field
    PASS_THROUGH value unchanged cell text unchanged

    Existing converters. @DictFormat would only install a converter on a field that does not already declare one, so an explicit @ExcelProperty(converter = ...) keeps winning.

    Validation. What would be rejected:

    • Malformed configuration - an entry that is not "code=label", or an annotation that gives both the inline entries and an enum type, or neither of them.
    • Ambiguity - the same code or the same label used twice, including two codes that become one value after conversion ("1" and "01" on an Integer field).
    • A code the field type cannot hold - "abc" on an Integer field, but also "1.9" or a value past Integer.MAX_VALUE, which the numeric converters would otherwise truncate or wrap instead of failing.
    • An empty label - {"1=", "0=Failure"}, where code 1 has nothing after the =. Writing a 1 would leave the cell empty, and an empty cell comes back as null instead of 1, so the value would be lost on the way back.

    Questions

    1. "code=label" strings, or a nested @DictEntry(code = ..., label = ...)? This is the one I would most like decided before writing anything. The examples above use the string form throughout, but only because a proposal needs one syntax to show - either would work:
    @DictFormat({"1=Success", "0=Failure"})
    
    @DictFormat({
        @DictEntry(code = "1", label = "Success"),
        @DictEntry(code = "0", label = "Failure")
    })

    Strings are shorter and read like the mapping they describe, but the compiler cannot see inside them - "1:Success" compiles and fails only when the model is built. Separate attributes make a missing code or label a compile error, and leave room for anything per-entry we might want later.

    1. Name/Place @DictFormat is chosen to sit beside @NumberFormat / @DateTimeFormat in annotation/format. Open to alternatives.

    Did I miss something? Happy to adjust any of the above.

  2. nkuprins commented on Aug 5, 2026

    @nkuprins
    Contributor

    Hi @delei, my apologies for pinning you, but I am afraid that my proposal may be lost in the sea of notifications, since this is an old issue. Should I create a new one and reference this or just wait🙏🏻

  3. delei commented on Aug 5, 2026

    @delei
    Member

    It's okay. We won’t overlook it.
    You can also create a new one to link to it. It’s just that this new proposal hasn’t yet attracted the community’s attention and support.

  4. MS-Jing commented on Aug 11, 2026

    @MS-Jing

    hi @nkuprins, my apologies for pinning you.
    This question has also been puzzling me all along.
    I initiated this discussion on the issue and provided a solution.
    #1005

  5. ergehenmeng commented on Aug 12, 2026

    @ergehenmeng

    As there has been no new version update for a long time, I took a look at the issues related to the translation of data dictionaries. If this PR Add composable annotations support is merged into the new version as soon as possible, it can solve many similar issues. Custom translation, dictionary translation, enum translation will be very simple. There is no need to pay too much attention to the business itself. Just leave the implementation method to the users.

  6. luo-zhan commented on Aug 26, 2026

    @luo-zhan

    关于这个问题,我觉得枚举转换带有业务含义,不是本项目该专注的工作,所以应该是先自行做好字段转换工作,再由Fesod导出。

    我之前正好开发了个字段转换组件Transformer,使用效果如下:

      /**
         * 单据类型
         */
        private String orderType;
    
        /**
         * 单据类型(描述)
         */
        @ExcelProperty("单据类型")
        @TransformEnum(OrderTypeEnum.class)  //将字段orderType的值经过枚举类的转换,设值到orderTypeName字段中
        private String orderTypeName;

    OrderTypeEnum枚举类定义,实现了Dict接口(也是单独一个枚举增强的项目EasyEnum,被Transformer引入),类定义变得非常简洁:

    public enum OrderTypeEnum implements Dict<String> {
    
        REQUIREMENT_ORDER("REQUIREMENT_ORDER", "要货单"),
        REFUND_ORDER("REFUND_ORDER", "退货单");
    
        OrderTypeEnum(String type, String desc) {
            init(type, desc); // 使用Dict方法初始化,自动拥有get方法
        }
    
    }

    Transformer不仅可以转换枚举类,也包括数据字典、rpc、db、自定义任何你想要的转换,然后使用时只需要用一行注解,非常方便。

    ps.不一定强制使用Dict接口,如果你有自己的枚举接口,可以很方便的基于Transformer的能力写一个自定义枚举转换器注解

    触发转换的方式有两种:

    1. 自动全局开启,在启动类上使用@EnableTransform,通过ResponseBodyAdvice自动对所有controller的响应体开启转换
    2. 手动使用,TransformUtil.transform(result);

    我认为除了“boolean转字符串”这种纯文本转换可以由Fesod来实现,但其他包括枚举转换、id->name这种有业务含义的字段转换都不该由Fesod负责,各司其职。


    其实,说到这里,上面的方式和自定义一个EnumConverter注入到Fesod的效果差不多,但是Transfermer专注字段转换能力,让每个工作变得更专注和解耦,扩展性更高

    另外,为了简化Fesod的使用,还开发了一个注解式导出的组件,也可以顺便看看,一个注解,就可以把查询接口变成导出接口,性能上还支持游标分页、流式传输ExportExcel

     @ExportExcel(limit = 50000, type = ExportType.CSV)
     @PostMapping("/api/requirement/deliveryCostStoreFee/paging")
     public Response<Paging<DeliveryCostStoreFreeDTO>> paging(@RequestBody PagingDeliveryCostStoreFreeRequest request) {

    配合Transformer有最简单的开发体验,已经在生产环境使用

  7. changed the title [-]希望支持注解字典转换[/-] [+][Enhancement] Support annotation-based dictionary conversion[/+] on Oct 5, 2026
  8. added
    enhancementNew feature or request
    help wantedExtra attention is needed
    and removed
    planningIt may be developed later
    on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions