Spring Boot中Enum的@JsonCreator在GET请求参数中不生效问题排查
问题:自定义@JsonCreator处理枚举别名未触发
我为枚举类MyEnum编写了自定义@JsonCreator方法,用于通过别名匹配枚举实例,但调用GET接口传入type参数为"12"时,该方法未触发,反而抛出枚举常量不存在的异常。
相关代码
Controller接口:
@GetMapping(value = "/path/{pathVar1}") public Response getValue( @PathVariable String pathVar1, @RequestParam(required = false, name = "type") MyEnum type)
枚举类MyEnum:
@AllArgsConstructor @Getter public enum MyEnum { A_12(Set.of("a", "12")); private Set<String> aliases; @JsonCreator public static MyEnum forValues(@JsonProperty("type") String type) { return Arrays.stream(MyEnum.values()) .filter(s -> s.getAliases().stream().anyMatch(a -> StringUtils.equalsIgnoreCase(a, type))) .findFirst() .orElseThrow(() -> new RuntimeException("aa")); } }
报错信息
Caused by: java.lang.IllegalArgumentException: No enum constant MyEnum.12
原因分析
@JsonCreator是Jackson的注解,仅在Jackson处理JSON序列化/反序列化场景下生效。但@RequestParam的参数解析默认使用Spring自带的StringToEnumConverterFactory,它只会尝试直接匹配枚举的原始名称(比如A_12),不会触发Jackson的@JsonCreator方法,因此传入别名"12"时会抛出常量不存在的异常。
解决方案
有两种常用方式实现枚举别名的请求参数解析:
方法一:实现Spring的Converter接口(全局生效)
自定义转换器并注册到Spring容器,让框架用它来解析MyEnum类型的参数:
@Component public class MyEnumConverter implements Converter<String, MyEnum> { @Override public MyEnum convert(String source) { return Arrays.stream(MyEnum.values()) .filter(s -> s.getAliases().stream().anyMatch(a -> StringUtils.equalsIgnoreCase(a, source))) .findFirst() .orElseThrow(() -> new IllegalArgumentException("无效的type参数:" + source)); } }
Spring会自动识别并注册该转换器,之后所有@RequestParam中的MyEnum类型参数都会通过它解析别名。
方法二:使用@InitBinder注册自定义编辑器(局部/全局生效)
局部生效(当前Controller)
在目标Controller中添加@InitBinder方法,注册自定义属性编辑器:
@Controller public class MyController { @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(MyEnum.class, new PropertyEditorSupport() { @Override public void setAsText(String text) throws IllegalArgumentException { MyEnum myEnum = Arrays.stream(MyEnum.values()) .filter(s -> s.getAliases().stream().anyMatch(a -> StringUtils.equalsIgnoreCase(a, text))) .findFirst() .orElseThrow(() -> new IllegalArgumentException("无效的type参数:" + text)); setValue(myEnum); } }); } // 你的接口方法... }
全局生效
定义@ControllerAdvice类,在其中添加@InitBinder方法,即可对所有Controller生效:
@ControllerAdvice public class GlobalEnumBinder { @InitBinder public void initBinder(WebDataBinder binder) { // 同上的编辑器注册逻辑 } }
内容的提问来源于stack exchange,提问作者Patan
相关产品推荐
相关产品推荐

