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

Spring Boot Enum多@JsonValue注解报错,需实现多格式JSON反序列化

解决方案:用@JsonCreator处理多格式输入,避免@JsonValue冲突

核心思路

@JsonValue注解只能标记一个方法(用于指定枚举序列化时的输出格式),不能同时标在两个方法上。要实现数字、大小写不敏感月份名称、甚至混合格式的输入支持,应该用@JsonCreator自定义反序列化逻辑,同时保留单个@JsonValue控制序列化输出。

完整代码示例

public enum MonthEnum {
    JANUARY(1, "January"),
    FEBRUARY(2, "February"),
    MARCH(3, "March"),
    APRIL(4, "April"),
    MAY(5, "May"),
    JUNE(6, "June"),
    JULY(7, "July"),
    AUGUST(8, "August"),
    SEPTEMBER(9, "September"),
    OCTOBER(10, "October"),
    NOVEMBER(11, "November"),
    DECEMBER(12, "December");

    private final int code;
    private final String name;
    private final String lowerName;

    MonthEnum(int code, String name) {
        this.code = code;
        this.name = name;
        this.lowerName = name.toLowerCase();
    }

    public int getCode() {
        return code;
    }

    public String getName() {
        return name;
    }

    public String getLowerName() {
        return lowerName;
    }

    // 自定义反序列化逻辑,覆盖所有输入格式
    @JsonCreator
    public static MonthEnum fromValue(Object input) {
        if (input == null) {
            throw new IllegalArgumentException("月份参数不能为空");
        }

        // 处理数字输入(1-12)
        if (input instanceof Integer) {
            int targetCode = (Integer) input;
            for (MonthEnum month : values()) {
                if (month.code == targetCode) {
                    return month;
                }
            }
        }

        // 处理字符串输入(纯名称、混合格式)
        if (input instanceof String) {
            String rawValue = ((String) input).trim();
            String lowerValue = rawValue.toLowerCase();

            // 先尝试转数字匹配code
            try {
                int code = Integer.parseInt(lowerValue);
                return fromValue(code);
            } catch (NumberFormatException e) {
                // 匹配大小写不敏感的月份名称
                for (MonthEnum month : values()) {
                    if (month.lowerName.equals(lowerValue)) {
                        return month;
                    }
                }

                // 处理混合格式(如"1-January"、"february-2")
                String[] parts = lowerValue.split("-");
                if (parts.length == 2) {
                    // 尝试code在前、名称在后的格式
                    tryMatchMixedFormat(parts[0].trim(), parts[1].trim());
                    // 尝试名称在前、code在后的格式
                    tryMatchMixedFormat(parts[1].trim(), parts[0].trim());
                }
            }
        }

        // 非法参数提示,替换成你已有的错误逻辑
        throw new IllegalArgumentException(
                String.format("无效的月份参数:%s。支持格式:1-12的数字、大小写不敏感的月份名称(如January/january)、或数字+名称的混合格式(如1-January)", input)
        );
    }

    // 辅助方法:验证混合格式的code和name是否匹配
    private static MonthEnum tryMatchMixedFormat(String codeStr, String nameStr) {
        try {
            int code = Integer.parseInt(codeStr);
            MonthEnum month = fromValue(code);
            if (month.lowerName.equals(nameStr)) {
                return month;
            }
        } catch (NumberFormatException | IllegalArgumentException ignored) {
            // 匹配失败,继续抛出最终异常
        }
        return null;
    }

    // 可选:指定序列化输出格式(二选一,或自定义序列化器输出多种)
    @JsonValue
    public int serializeAsCode() {
        return code;
    }

    // 如果需要序列化输出名称,替换上面的方法:
    // @JsonValue
    // public String serializeAsName() {
    //     return name;
    // }
}

关键说明

  1. 移除多@JsonValue注解:只保留一个@JsonValue用于控制序列化时的输出格式(数字或名称,根据业务需求选择),解决注解冲突问题。
  2. @JsonCreator处理多格式输入:
    • 优先处理数字类型输入;
    • 字符串类型先尝试转数字,失败后匹配大小写不敏感的月份名称;
    • 额外支持数字+名称的混合格式验证;
    • 不匹配时抛出你已定义的非法参数提示。
  3. 扩展性:如果需要支持更多输入格式(如缩写"Jan"),只需在字符串匹配逻辑中添加对应判断即可。

内容的提问来源于stack exchange,提问作者Gianni Spear

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 22:57:33