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

使用Jackson反序列化泛型枚举时遇到的异常问题

Jackson泛型枚举反序列化问题解决方法

我有如下Java类结构:

public class Lame<E extends Enum<E>> {
    private Enum<E> abstractType;
    
    public Enum<E> getAbstractType() {
        return abstractType;
    }
    
    @JsonCreator
    public Lame(E type) {
        this.abstractType = type;
    }
}

public class InheritLame extends Lame<InheritLame.CounterType> {
    public enum CounterType {
        ONE,
        TWO,
        THREE;
    }
    
    public String name;
    
    @JsonCreator
    public InheritLame(CounterType type) {
        super(type);
        this.name = "NAME";
    }
    
    public String getName() {
        return this.name;
    }
}

当实例化InheritLame对象(传入CounterType.ONE)并序列化为JSON时,输出为:

{"abstractType":"ONE","name":"NAME"}

但将该JSON反序列化为InheritLame对象时,抛出异常:

com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `InheritLame$CounterType` from String "abstractType": not one of the values accepted for Enum class: [TWO, ONE, THREE]
at [Source: (String)"{"abstractType":"ONE","name":"NAME"}"; line: 1, column: 2]
at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67)...

实际项目中存在近50种不同枚举类型对应基类的private Enum<T> abstractType字段,通过调整基类层级结构解决过于繁琐,尝试过多种Jackson注解未解决,寻求可行方案。


解决方案:给构造器参数添加@JsonProperty注解

问题根源在于Jackson无法自动识别构造器参数与JSON字段的映射关系。默认情况下,带@JsonCreator的单参数构造器会尝试将整个JSON对象作为参数传入,但构造器期望的是枚举类型,导致Jackson错误地将JSON字段名(而非字段值)当作枚举值解析。

只需在基类和子类的构造器参数上添加@JsonProperty注解,指定对应的JSON字段名即可解决:

修改后的基类:

public class Lame<E extends Enum<E>> {
    private Enum<E> abstractType;
    
    public Enum<E> getAbstractType() {
        return abstractType;
    }
    
    @JsonCreator
    public Lame(@JsonProperty("abstractType") E type) {
        this.abstractType = type;
    }
}

修改后的子类:

public class InheritLame extends Lame<InheritLame.CounterType> {
    public enum CounterType {
        ONE,
        TWO,
        THREE;
    }
    
    public String name;
    
    @JsonCreator
    public InheritLame(@JsonProperty("abstractType") CounterType type) {
        super(type);
        this.name = "NAME";
    }
    
    public String getName() {
        return this.name;
    }
}

这样Jackson就能明确知晓构造器的type参数对应JSON中的abstractType字段,正确提取字段值"ONE"并反序列化为对应的枚举实例。


备选方案:使用自定义反序列化器(复杂场景)

如果上述方法无法满足需求(比如需要更复杂的类型推断),可以为基类的abstractType字段自定义反序列化器:

  1. 创建自定义反序列化器:
public class EnumDeserializer extends JsonDeserializer<Enum<?>> {
    @Override
    public Enum<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        // 获取当前需要反序列化的目标类型
        JavaType targetType = ctxt.getContextualType();
        if (targetType == null || !targetType.isEnumType()) {
            throw new IllegalArgumentException("Target type is not an enum");
        }
        Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) targetType.getRawClass();
        String value = p.getValueAsString();
        return Enum.valueOf(enumClass, value);
    }
}
  1. 在基类字段上添加注解指定反序列化器:
public class Lame<E extends Enum<E>> {
    @JsonDeserialize(using = EnumDeserializer.class)
    private Enum<E> abstractType;
    
    // 其余代码不变
}

这种方法适用于需要动态推断枚举类型的场景,无需在每个构造器上添加注解,但实现相对复杂。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:17:45