如何使用@ConfigurationProperties进行列表值或数组值映射?

时间:2015-09-06 04:10:52

标签: spring-boot

我有一个项目,我想配置字符串键控的“组” 字符串数组的字符串键控“命令”。也就是说,我想 能够在config.yml中表达类似下面的内容,以及 通过@ConfigurationProperties(prefix =“config.base”)消费:

---
config:
  base:
    "bin group":
    - "Directory Listing": ["/bin/ls", "-la"]
    - "Server Date/Time": ["/bin/date", "-u"]
    "usr/bin group":
    - "Find .txt Files": ["/usr/bin/find", ".", "-name", "*.txt"]
    "usr/local/bin group":
    - "Tree Listing": ["/usr/local/bin/tree"]

理想情况下,我希望@ConfigurationProperties对象为LinkedHashMap<String, LinkedHashMap<String, String[]>>

但我无法弄清楚如何做到这一点。或者任何合理接近的东西。 我得到的最接近的如下:

package us.w7tek.bug;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

import javax.annotation.PostConstruct;
import java.util.LinkedHashMap;

@EnableConfigurationProperties
@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }

    @ConfigurationProperties("someConfig")
    @Bean
    public ExternalizedConfig externalizedConfig() { return new ExternalizedConfig(); }

    public static class ExternalizedConfig extends LinkedHashMap<String, String[]> {
        // oops, @ConfigurationProperties ends up putting LinkedHashMap<String, String> in the values of the top-level mapping,
        // and that second-level LinkedHashMap has keys that could have come from Integer#toString
    }

    @Controller
    public static class ControllerThatConsumesConfig {
        private static final String A_KEY_THAT_COULDNT_BE_A_PROPERTY_NAME = "this == config cannot be expressed as a bean with properties, because the keys cannot be made into Java language identifiers for bean property setters and getters";

        @Autowired
        ExternalizedConfig config;

        @PostConstruct
        void init() {
            String[] strings = config.get(A_KEY_THAT_COULDNT_BE_A_PROPERTY_NAME);  //  ClassCastException occurs here

            // doesn't have to occur in @PostConstruct, that was just a convenient place for my demo.
        }
    }
}

在项目中使用以下示例application.yml

---
someConfig:
    "this is a key": ["this", "value", "is", "not", "an", "String[]"]
    "this is another key": ["it", "is", "deserialized", "as", "LinkedHashMap", "having", "keys", "like", "\"0\"", "and", "\"1\"", "etc."]
    "this == config cannot be expressed as a bean with properties, because the keys cannot be made into Java language identifiers for bean property setters and getters": ["thereby", "subverting", "Java's", "static", "typing", "and", "resulting", "in", "ClassCastException", "at", "runtime"]

如评论中所示,当Spring Boot @ConfigurationProperties绑定器创建LinkedHashMap<String, LinkedHashMap<String, LinkedHashMap<String, String>>>类型的对象并将其放在config字段中时,该代码会爆炸。当然,只要任何方法根据其静态声明的类型访问config,就会出现ClassCastException。我不确定是否认为这是@ConfigurationProperties使用的属性绑定器代码的错误,或者只是我的严重误解。我认为上面的代码是展示问题的最简单的代码。也可以在https://github.com/w7tek/demo-configproperties-bug.git找到,以防有人想编译并运行以查看堆栈跟踪。

有没有人有@ConfigurationProperties收藏品的例子?通过简单地将声明的类型与Spring反序列化的实际类型相匹配,我可以从我所处的位置看到前进的方向,但最终使用起来非常不方便。我真的希望将此配置的最内层值作为List&lt;&gt;或数组类型,如果可能的话,但我无法弄清楚如何。

1 个答案:

答案 0 :(得分:1)

这是您需要的:

不要使用tab,每个内部元素使用2个空格。

config:
  base:
    "bin group":
      "Directory Listing": ["/bin/ls", "-la"]
      "Server Date/Time": ["/bin/date", "-u"]
    "usr/bin group":
      "Find txt Files": ["/usr/bin/find", ".", "-name", "*.txt"]
    "usr/local/bin group":
      "Tree Listing": ["/usr/local/bin/tree"]

这是Configuration类:

@Configuration
@ConfigurationProperties(prefix  = "config")
public class Conf_Test {

    private LinkedHashMap<String, LinkedHashMap<String, List<String>>> base;

    public LinkedHashMap<String, LinkedHashMap<String, List<String>>> getBase() {
    return base;
    }

    public void setBase(LinkedHashMap<String, LinkedHashMap<String, List<String>>> base) {
    this.base = base;
    }

}

显然,你不能使用&#34;。&#34;在地图键内部,它只是剪切了键,所以我删除了&#34;查找.txt文件&#34;键。另外,spring-boot不支持map中的自动groving数组,因此现在不能使用String []但list正在运行。