RestTemplate发送Enum枚举列表报参数类型转换异常如何解决?
错误核心原因
该异常由两点不匹配导致:
@JsonValue注解仅对JSON格式的请求体/响应生效,Spring MVC默认的URL查询参数转换器不会识别该注解,默认使用枚举类的name()属性(即VALUE_1、VALUE_2)做匹配- 你自定义的枚举
toString()方法返回的是value字段值,拼接查询参数时传递的是value-1、value-2,和默认转换器的匹配规则不一致,导致转换失败
解决方案
方案1:全局配置枚举转换器(推荐,兼容所有带@JsonValue的枚举)
- 自定义通用枚举转换器工厂,读取枚举的
@JsonValue值做匹配:
import com.fasterxml.jackson.annotation.JsonValue; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.ConverterFactory; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class EnumJsonValueConverterFactory implements ConverterFactory<String, Enum<?>> { @Override public <T extends Enum<?>> Converter<String, T> getConverter(Class<T> targetType) { return new EnumJsonValueConverter<>(targetType); } private static class EnumJsonValueConverter<T extends Enum<?>> implements Converter<String, T> { private final Map<String, T> valueMap = new HashMap<>(); private final Class<T> enumType; public EnumJsonValueConverter(Class<T> enumType) { this.enumType = enumType; T[] enumConstants = enumType.getEnumConstants(); for (T enumObj : enumConstants) { try { for (Field field : enumType.getDeclaredFields()) { if (field.isAnnotationPresent(JsonValue.class)) { field.setAccessible(true); Object value = field.get(enumObj); if (value != null) { valueMap.put(value.toString().trim(), enumObj); } break; } } } catch (IllegalAccessException e) { throw new RuntimeException("枚举@JsonValue值读取失败", e); } } } @Override public T convert(String source) { T result = valueMap.get(source.trim()); if (result == null) { throw new IllegalArgumentException(String.format("枚举类型[%s]不存在匹配值[%s]", enumType.getName(), source)); } return result; } } }
- 将转换器注册到Spring MVC配置中:
import org.springframework.context.annotation.Configuration; import org.springframework.format.FormatterRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverterFactory(new EnumJsonValueConverterFactory()); } }
该方案无需修改发送端代码,接收端所有带@JsonValue注解的枚举参数都会自动按自定义value值转换。
方案2:修改发送端传参逻辑(无侵入接收端,快速验证)
如果不想修改全局配置,可直接在发送端传递枚举的name()属性,适配默认转换器规则:
// 把原来的.queryParam("taskNames", taskNames)替换为以下代码 .queryParam("taskNames", taskNames.stream().map(Enum::name).collect(Collectors.toList()))
该方案无需修改接收端代码,缺点是请求参数中的枚举值会变为VALUE_1、VALUE_2,而非自定义的value-1格式。
内容的提问来源于stack exchange,提问作者Xolo12er
相关产品推荐
相关产品推荐

