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

Jackson枚举反序列化异常:为何需同时使用@JsonCreator与@JsonValue?

低版本Jackson枚举反序列化需配合@JsonCreator的原因

核心差异:Jackson版本对@JsonValue的处理逻辑变化

  • Jackson 2.11之前(如你使用的2.10.2):
    @JsonValue仅作用于序列化阶段——它告诉Jackson将枚举实例序列化为getCode()返回的数值,但反序列化时,Jackson的默认逻辑并不会自动逆向使用这个规则。此时Jackson会优先按枚举的ordinal(声明顺序的序号,从0开始)来匹配输入值,其次才会尝试匹配枚举名称。
    你的DeliveryType枚举中,A的ordinal是0、code是1;B的ordinal是1、code是2。所以反序列化输入1时,Jackson会匹配ordinal=1的B,输入0匹配ordinal=0的A,完全忽略了code的值。这时候必须通过@JsonCreator标注静态工厂方法fromCode(),明确告诉Jackson反序列化时要根据code值查找对应的枚举实例。

  • Jackson 2.11及之后(如你升级的2.15.2):
    官方优化了枚举反序列化逻辑:当枚举类存在@JsonValue注解时,Jackson会自动启用逆向映射——遍历所有枚举实例,用输入值匹配每个实例的@JsonValue返回值,找到对应的枚举。因此不需要额外添加@JsonCreator,Jackson就能自动根据code值完成反序列化。

你的枚举代码示例

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.stream.Stream;

@Getter
@AllArgsConstructor
public enum DeliveryType {
    A (1, "Delivery A", "X"),
    B (2, "Delivery B", "Y");

    private final Integer code;
    private final String description;
    private final String textCode;

    @JsonCreator
    public static DeliveryType fromCode(final Integer code) {
        return Stream.of(DeliveryType.values())
                .filter(type -> type.code == code)
                .findFirst()
                .orElse(null);
    }

    @JsonValue
    public Integer getCode() {
        return code;
    }
}

测试代码示例

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class DeliveryTypeTest {
    private final ObjectMapper objectMapper;
    private final ObjectWriter writer;

    public DeliveryTypeTest() {
        this.objectMapper = new ObjectMapper();
        writer = objectMapper.writerWithDefaultPrettyPrinter();
    }

    @Test
    public void serialize() throws JsonProcessingException {
        final DeliveryType type = DeliveryType.A;
        final String json = writer.writeValueAsString(type);
        Assertions.assertEquals(DeliveryType.A.getCode().toString(), json);
    }

    @Test
    public void deserialize() throws JsonProcessingException {
        final String jsonValue = DeliveryType.A.getCode().toString();
        final DeliveryType deSerializedType = objectMapper.readValue(jsonValue, DeliveryType.class);
        Assertions.assertEquals(DeliveryType.A, deSerializedType);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 03:34:57