java - 无法使用 Map 调用 SPeL Expression.setValue()

标签 java spring spring-el

我正在编写一些代码,以允许使用 Spring 表达式语言进行动态属性更改。我传入 bean 名称、属性名称和新值的表达式(所有字符串)。

这适用于字符串、整数、 boolean 值和列表类型的属性。我无法让 map 属性正常工作。我查看了 SPeL 文档,包括示例,但我没有发现我所做的有任何问题。我返回的异常没有帮助。

忽略try/catch block ,基本代码如下:

ExpressionParser parser = new SpelExpressionParser();
Expression parsedPropertyNameExpression = parser.parseExpression(propertyName);
SimpleEvaluationContext evalContext = SimpleEvaluationContext.forReadWriteDataBinding().build();
Object currentValue = parsedPropertyNameExpression.getValue(evalContext, bean);
parsedPropertyNameExpression.setValue(evalContext, bean, expression);

当我的“表达式”是“789, 0123, 345”并且我设置的属性是列表时,效果非常好。

但是,当我设置 Map ("") 类型的属性(其中表达式值为“{abc:'def',ghi:'jkl'}”)时,出现以下异常:

 org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<java.lang.String, java.lang.String>]

我尝试了该表达式字符串的不同变体,但结果基本相同。

更新:

我注意到以下SO帖子:How to inject a Map using the @Value Spring Annotation? .

不接受的答案之一提到在属性中定义 Map 并使用 @Value 注释注入(inject)它,我认为这是使用类似的机制。我怎样才能在代码中做到这一点?

最佳答案

The exception I get back is not helpful.

No converter found capable of converting from type [java.lang.String] to type [java.util.Map]

我觉得很清楚。

没有内置支持将 map 的字符串表示形式转换为 Map 对象。

您可以注册自定义函数,或在 SpEL 表达式中使用 Jackson ObjectMapper bean 引用。

编辑

这是一种方法(使用 Jackson 的自定义 Converter)...

public class So55485198Application {

    public static void main(String[] args) {
        Bean bean = new Bean();
        getAndSet("list", bean, "abc, def");
        getAndSet("map", bean, "{'abc':'def'}");
    }

    public static void getAndSet(String propertyName, Bean bean, String expression) {
        ExpressionParser parser = new SpelExpressionParser();
        Expression parsedPropertyNameExpression = parser.parseExpression(propertyName);
        DefaultConversionService conversionService = new DefaultConversionService();
        conversionService.addConverter(new StringToMapConverter());
        SimpleEvaluationContext evalContext = SimpleEvaluationContext.forReadWriteDataBinding()
                .withConversionService(conversionService)
                .build();
        Object currentValue = parsedPropertyNameExpression.getValue(evalContext, bean);
        System.out.println("old:" + currentValue);
        parsedPropertyNameExpression.setValue(evalContext, bean, expression);
        System.out.println("new:" + parsedPropertyNameExpression.getValue(evalContext, bean));
    }

    static class StringToMapConverter implements Converter<String, Map<String, String>> {

        private static final ObjectMapper objectMapper = new ObjectMapper();

        static {
            objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        }

        @SuppressWarnings("unchecked")
        @Override
        public Map<String, String> convert(String source) {
            try {
                return this.objectMapper.readValue(source, LinkedHashMap.class);
            }
            catch (IOException e) {
                e.printStackTrace();
                throw new IllegalStateException(e);
            }
        }

    }

    static class Bean {

        private List<String> list = new ArrayList<>(Arrays.asList("foo", "bar"));

        private Map<String, String> map = new HashMap<>(Collections.singletonMap("foo", "bar"));

        public List<String> getList() {
            return this.list;
        }

        public void setList(List<String> list) {
            this.list = list;
        }

        public Map<String, String> getMap() {
            return this.map;
        }

        public void setMap(Map<String, String> map) {
            this.map = map;
        }

    }

}

关于java - 无法使用 Map 调用 SPeL Expression.setValue(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55485198/

相关文章:

spring - 重新加载静态内容 Spring Boot 应用程序

java - spring 如何知道新的请求或 session ?

java - 在 Spring application.properties 文件中声明对象列表

jakarta-ee - 通过名称访问 session bean,无需 JNDI 查找

java - MP4Parser 改变视频方向

java - @Around 建议在 Spring AOP 中究竟是如何工作的?

java - 如何在 SpEL 中转义值?

java - 使用 spring el 将值获取到 map 中

java - 一个字符串包含多少字节?

java - 封装私有(private)变量和公共(public)方法需要什么?而不是直接声明公共(public)变量