SpEL类型转换异常:LinkedHashMap转String失败及自定义转换器无效
SpEL模板字符串评估时LinkedHashMap转String失败问题
问题场景
使用SpEL评估模板字符串,核心代码如下:
Expression exp = parser.parseExpression(templatedString, templateParserContext); return exp.getValue(readOnlyEvalContext, contextRoot);
当模板字符串为"flow.config: ${flow.config}",且contextRoot中的flow.config是Jackson反序列化生成的LinkedHashMap<String, Object>时,抛出类型转换异常:
org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from java.util.LinkedHashMap<?, ?> to java.lang.String
尝试的无效解决方案
为将LinkedHashMap序列化为JSON字符串,创建自定义转换器并通过WebMvcConfigurer注册:
Converter配置类
@Configuration public class ConverterConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new ConverterLinkedHashMapToString()); } }
自定义转换器
@Component public class ConverterLinkedHashMapToString implements Converter<LinkedHashMap<?, ?>, String> { @Override public String convert(LinkedHashMap<?, ?> source) { return objMapper.writeValueAsString(source); } @Override public <U> Converter<LinkedHashMap<?, ?>, U> andThen(Converter<? super String, ? extends U> after) { return Converter.super.andThen(after); } }
无论如何调整,转换器均未生效,仍持续抛出相同异常。
完整异常栈
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from java.util.LinkedHashMap<?, ?> to java.lang.String at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:87) ~[spring-expression-5.3.22.jar:5.3.22] at org.springframework.expression.common.ExpressionUtils.convertTypedValue(ExpressionUtils.java:57) ~[spring-expression-5.3.22.jar:5.3.22] at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:378) ~[spring-expression-5.3.22.jar:5.3.22] at org.springframework.expression.common.CompositeStringExpression.getValue(CompositeStringExpression.java:129) ~[spring-expression-5.3.22.jar:5.3.22] at org.springframework.expression.common.CompositeStringExpression.getValue(CompositeStringExpression.java:43) ~[spring-expression-5.3.22.jar:5.3.22] [...] ... 3 common frames omitted Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.util.LinkedHashMap<?, ?>] to type [java.lang.String] at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322) ~[spring-core-5.3.22.jar:5.3.22] at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-5.3.22.jar:5.3.22] at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:82) ~[spring-expression-5.3.22.jar:5.3.22] ... 38 common frames omitted
问题原因及解决方案
原因
通过WebMvcConfigurer注册的转换器仅作用于Spring MVC的请求响应转换流程,SpEL的表达式求值上下文(EvaluationContext)使用独立的ConversionService,两者并不共用,因此自定义转换器无法被SpEL识别。
解决方案
需要将自定义转换器注册到SpEL使用的ConversionService中,具体步骤如下:
- 创建自定义ConversionService Bean
@Configuration public class ConversionConfig { @Bean public ConversionService spelConversionService(ObjectMapper objMapper) { GenericConversionService conversionService = new GenericConversionService(); conversionService.addConverter(new ConverterLinkedHashMapToString(objMapper)); return conversionService; } }
- 修改自定义转换器,注入ObjectMapper
public class ConverterLinkedHashMapToString implements Converter<LinkedHashMap<?, ?>, String> { private final ObjectMapper objMapper; public ConverterLinkedHashMapToString(ObjectMapper objMapper) { this.objMapper = objMapper; } @Override public String convert(LinkedHashMap<?, ?> source) { try { return objMapper.writeValueAsString(source); } catch (JsonProcessingException e) { throw new RuntimeException("序列化LinkedHashMap为JSON失败", e); } } }
- 将自定义ConversionService绑定到SpEL的EvaluationContext
在构建readOnlyEvalContext时,设置自定义的ConversionService:
@Autowired private ConversionService spelConversionService; // ... StandardEvaluationContext readOnlyEvalContext = new StandardEvaluationContext(contextRoot); readOnlyEvalContext.setConversionService(spelConversionService); Expression exp = parser.parseExpression(templatedString, templateParserContext); return exp.getValue(readOnlyEvalContext);
如果你的readOnlyEvalContext是通过其他方式创建的,确保调用其setConversionService方法传入自定义的ConversionService即可。
内容的提问来源于stack exchange,提问作者Gurtz
相关产品推荐
相关产品推荐

