【Java】 解决OriginTrackedValue incompatible with String 问题

时间:2022-04-01 00:58:31

问题

在Springboot项目读取yaml文件时出现类型转换错误,如下所示:

org.springframework.boot.origin.OriginTrackedValue incompatible with java.lang.String

分析

现遇到了一个场景需要动态读取配置信息,于是打算通过Environment去获取环境变量中的application配置:

PropertySource<?> activeSource = ((StandardServletEnvironment)env).getPropertySources().get("applicationConfig: [classpath:/application-" + activeProfile + ".yml]");
Map<String, String> activeAppMap =(Map<String, String>)activeSource.getSource();

如上代码所示,我们是可以通过Map<String,String>去接住PropertySource类型的Source对象。因为activeSource.getSource()返回的是一个Object对象。

但这样的话在循环activeAppMap获取Key、Value时将会出错。通过源码得知activeSource.getSource()获取到的虽然是一个Object对象,但实际上它是一个LinkedHashMap,而里面的Value是一个OriginTrackedValue对象。这个OriginTrackedValue对象是通过origin去存储对象的,因此只能够通过origin.getValue()方法才能够获取到真正的值。

所以真正getSource方法返回是LinkedHashMap<String,OriginTrackedValue>类型,而我们通过Map去做向上转型也是可以的。整体代码如下所示:

private Map<String, String> getYmlConfig(Environment env, String prefix) 
{
Map<String, String> reMap = new HashMap<>();
Map<String, OriginTrackedValue> appMap = new LinkedHashMap<>();
String[] activeProfiles = env.getActiveProfiles();
if (activeProfiles.length > 0) {
for (String activeProfile : activeProfiles) {
PropertySource<?> activeSource =
((StandardServletEnvironment)env).getPropertySources().get("applicationConfig:[classpath:/application-" + activeProfile + ".yml]");
Map<String, OriginTrackedValue> activeAppMap =(Map<String,
OriginTrackedValue>)activeSource.getSource();
if (null != activeAppMap && !activeAppMap.isEmpty()) {
appMap.putAll(activeAppMap);
}
}
}
PropertySource<?> source =
((StandardServletEnvironment)env).getPropertySources().get("applicationConfig: [classpath:/config/application.yml]");
Map<String, OriginTrackedValue> localAppMap = (Map<String,
OriginTrackedValue>)source.getSource();
if (null != localAppMap && !localAppMap.isEmpty()) {
appMap.putAll(localAppMap);
}
if (null != appMap && !appMap.isEmpty()) {
appMap.forEach((k, v) -> {
if (k.contains(prefix)) {
reMap.put(k, String.valueOf(v.getValue()));
}
});
}
return reMap;
}