Spring @Value 加载Map 结构时,报:Cannot convert value UnmodifiableRandomAccessList to Map

  • Post author:
  • Post category:其他


一:

Spring @Value 加载Map 结构时,报:Cannot convert value of type ‘java.util.Collections$UnmodifiableRandomAccessList’ to required type ‘java.util.Map

org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'java.util.Collections$UnmodifiableRandomAccessList' to required type 'java.util.Map'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.util.Collections$UnmodifiableRandomAccessList' to required type 'java.util.Map': no matching editors or conversion strategy found
	at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:74)
	at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:54)
	at com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener.resolvePropertyValue(AutoUpdateConfigChangeListener.java:115)
	at com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener.updateSpringValue(AutoUpdateConfigChangeListener.java:90)
	at com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener.onChange(AutoUpdateConfigChangeListener.java:66)
	at com.ctrip.framework.apollo.internals.AbstractConfig$2.run(AbstractConfig.java:440)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
	at java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.util.Collections$UnmodifiableRandomAccessList' to required type 'java.util.Map': no matching editors or conversion strategy found
	at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:306)
	at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:125)
	at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:61)

二:

Map 配置如下:
@Value("#{${small.flow.by.assign.map:null}}")
private Map<String, String> smallFlowByAssignMap;

small.flow.by.assign.map 配置的值为: { } 或者{}  等, Spring 会将 {}  转换为: List 类型,


注: List 类型的默认值是: {}

如:

@Value("#{${not.execute.new.regulation.List:{}}}")
private List<String> notExecuteNewRegulations;

跟踪源码发现:

org.springframework.expression.spel.standard.InternalSpelExpressionParser#maybeEatInlineListOrMap

@Value 中对应的属性如果值:

1:开始为

{

后面跟

}

会转换为List:



// empty list ‘{}’




2:开始为

{

后面跟

:

会转换为Map



// empty map ‘{:}’




如果需要使用@Value 声明对象属性为Map,也可以采用间接方式处理:



如 示例代码:   使用属性的set 方法注入属性时,将配置的属性声明为String 类型,然后通过Json 转换为Map类型

 @Value("${small.flow.by.assign.mapStr:{}}")
    public void setSmallFlowByAssignMap(String assignMapStr) {

        this.smallFlowByAssignMap = json().toObject(assignMapStr, new TypeReference<Map<String, Integer>>() {
        });
    }

三: #{…}和${…}  用法: 参考:

https://www.cnblogs.com/candlia/p/11919934.html

#{…}和${…}

${…}用法

通过@Value(“${spelDefault.value}”)可以获取属性文件中对应的值,但是如果属性文件中没有这个属性,则会报错。可以通过赋予默认值解决这个问题,如

@Value("${test.value:127.0.0.1}")

#{…}用法

#{…}的{}里面的内容必须符合SpEL表达式,详细的语法,以后可以专门开新的文章介绍,这里只演示简单用法:

${…}和#{…}混合使用

${…}和#{…}可以混合使用,如下文代码执行顺序:通过

${server.name}

从属性文件中获取值并进行替换,然后就变成了 执行SpEL表达式

#{'server1,server2,server3'.split(',')}

// SpEL: 传入一个字符串,根据”,”切分后插入列表中, #{}和${}配置使用(注意单引号,注意不能反过来${}在外面,#{}在里面)

@Value("#{'${server.name}'.split(',')}") private List<String> servers;

在上文中在#{}外面,${}在里面可以执行成功,那么反过来是否可以呢${}在外面,#{}在里面,是不能。

因为spring执行${}是时机要早于#{}。${}在外面,#{}在里面是非法操作。

小结

#{…} 主要用于加载外部属性文件中的值

${…} 用于执行SpEl表达式,并将内容赋值给属性

#{…} 和${…} 可以混合使用,但是必须#{}外面,${}在里面



版权声明:本文为u013833031原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。