我需要用来自 application.yml
的值动态填充 POJO,因为前缀是在运行时计算的。
我已经阅读了 Spring 源代码,发现它使用 org.springframework.boot.context.properties.bind.Binder
类来使用给定前缀的属性填充给定类型的 POJO。精彩!
虽然,下面的代码抛出了一个异常:
// my custom prefix has CamelCase style, but I've found that props
// are case insensitive and I simply can lowercase it to make it valid
var configProp = ConfigurationPropertyName.ofIfValid(pojoPropPrefix.toLowerCase());
var pojos = binder.bindOrCreate(
configProp,
Bindable.listOf(Pojo.class),
null);
抛出的异常(最深层的原因):
Caused by: org.springframework.boot.context.properties.source.InvalidConfigurationPropertyNameException: Configuration property name 'this$0' is not valid
at org.springframework.boot.context.properties.source.ConfigurationPropertyName.elementsOf(ConfigurationPropertyName.java:577)
at org.springframework.boot.context.properties.source.ConfigurationPropertyName.probablySingleElementOf(ConfigurationPropertyName.java:550)
at org.springframework.boot.context.properties.source.ConfigurationPropertyName.append(ConfigurationPropertyName.java:207)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$4(Binder.java:447)
at org.springframework.boot.context.properties.bind.ValueObjectBinder$ConstructorParameter.bind(ValueObjectBinder.java:290)
at org.springframework.boot.context.properties.bind.ValueObjectBinder.bind(ValueObjectBinder.java:71)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$5(Binder.java:451)
at org.springframework.boot.context.properties.bind.Binder$Context.withIncreasedDepth(Binder.java:571)
at org.springframework.boot.context.properties.bind.Binder$Context.withDataObject(Binder.java:557)
at org.springframework.boot.context.properties.bind.Binder$Context.access$300(Binder.java:512)
at org.springframework.boot.context.properties.bind.Binder.bindDataObject(Binder.java:449)
at org.springframework.boot.context.properties.bind.Binder.bindObject(Binder.java:390)
at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:319)
... 45 more
Binder
尝试绑定 my.prefix.PojoList[0]
并以某种方式尝试填充 0
属性而不是填充列表。
我找到了解决方法 - 而是将 props 绑定到 LinkedHashMap
var responses = binder.bindOrCreate(
configProp,
// does not work, tries to instantiate interface Map
// Bindable.mapOf(String.class, ResponsesElement.class),
Bindable.of(ResolvableType.forType(new ParameterizedTypeReference<LinkedHashMap<String, Object>>() {})),
null);
但以上代码仅适用于 LinkedHashMap<String,
Object
>
(生成嵌套地图),而不适用于 Pojo
.
如果我使用 LinkedHashMap<String, Pojo>
,它仍然会抛出“配置属性名称 'this$0' 无效”异常。
也许有人知道为什么会引发此异常,以及是否有机会填充 Pojo
列表?
我找到了带有 LinkedHashMap<String, Object>
的解决方案,只需在其上使用 ObjectMapper#convert
。
但我认为必须有更优雅的解决方案,因为这个 ObjectMapper
东西只允许从 Map<String, Object>
转换为 Map<String, Pojo>
,因为源映射的 String
键({{1 }}、"0"
等)。
仍然无法直接从 "1"
转换为 Map<String, Object>
。
最初的问题是关于List<Pojo>
。