You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何阻止Jackson解析JSON时接受枚举的序数值?

解决Jackson枚举反序列化时允许序数输入的问题

这个问题是Jackson的默认行为导致的——它默认支持枚举的名称、序数、以及@JsonProperty指定的别名三种方式来反序列化枚举值。要让解析器只接受你定义的"HIGH"、"LOW"、"MEDIUM"这三个字符串输入,完全拒绝数字序数,这里有几种实用的解决方案:

方法一:通过ObjectMapper配置全局禁用序数支持

最快捷的方式是直接配置你的ObjectMapper,开启数字枚举报错的特性:

ObjectMapper objectMapper = new ObjectMapper();
// 禁用使用toString()匹配枚举的方式(可选,进一步收紧规则)
objectMapper.disable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
// 开启遇到数字类型枚举输入时抛出异常
objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);

配置完成后,当输入{"priority": 0}这类数字值时,Jackson会直接抛出JsonMappingException,不会再将其映射为对应的枚举实例。

方法二:给枚举类添加自定义反序列化器

如果需要更灵活的控制(比如支持大小写不敏感、自定义错误提示等),可以给枚举写一个专属的反序列化器:

首先实现反序列化器类:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.io.IOException;

public class PriorityDeserializer extends StdDeserializer<Priority> {

    public PriorityDeserializer() {
        super(Priority.class);
    }

    @Override
    public Priority deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String inputValue = p.getText().trim();
        // 遍历枚举,仅匹配@JsonProperty指定的字符串值
        for (Priority priority : Priority.values()) {
            JsonProperty annotation = priority.getClass().getField(priority.name()).getAnnotation(JsonProperty.class);
            if (annotation != null && annotation.value().equals(inputValue)) {
                return priority;
            }
        }
        // 不匹配时抛出自定义异常
        throw ctxt.weirdStringException(inputValue, Priority.class, "仅支持\"LOW\"、\"MEDIUM\"、\"HIGH\"三种优先级值");
    }
}

然后在你的枚举类上添加@JsonDeserialize注解指定这个反序列化器:

@JsonDeserialize(using = PriorityDeserializer.class)
public enum Priority {
    @JsonProperty("LOW")
    LOW(100),
    @JsonProperty("MEDIUM")
    MEDIUM(200),
    @JsonProperty("HIGH")
    HIGH(300);

    private int priority;

    Priority(int i) {
        this.priority = i;
    }

    public int getPriority() {
        return priority;
    }
}

这种方式可以完全掌控枚举的匹配逻辑,适合有特殊业务需求的场景。

方法三:Spring Boot项目全局配置

如果你在Spring Boot项目中,可以通过配置类统一设置Jackson的枚举反序列化规则,不用每个ObjectMapper单独配置:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
        mapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS);
        return mapper;
    }
}

这样整个项目的所有枚举反序列化都会遵循这个严格规则,避免重复配置。


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

火山引擎 最新活动