Spring Boot ConfigurationProperties 动态绑定 - 对象列表

时间:2020-12-21 09:05:03

标签: java spring

我需要用来自 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>

0 个答案:

没有答案
相关问题