如何阻止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




