2015-09-06 519 views
1

我有一个项目,我想配置字符串键“组” 字符串键“命令”的字符串数组。也就是说,我想 能够表达的东西像config.yml以下,并通过 消费@ConfigurationProperties(PREFIX =“config.base”):如何使用@ConfigurationProperties进行列表值或数组值映射?

--- 
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"] 

理想的情况下,我d想@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"] 

正如评论指出,该代码爆炸当弹簧引导@ConfigurationProperties粘结剂创建一个LinkedHashMap<String, LinkedHashMap<String, LinkedHashMap<String, String>>>类型的对象,并将其放在config字段中。当然,只要有任何方法根据其静态声明类型访问config,就会发生ClassCastException。我不确定是否相信这是一个使用@ConfigurationProperties所使用的属性联编程序代码的错误,或者只是我的重大误解。我认为上面的代码是展示问题的最简单的事情。也可在https://github.com/w7tek/demo-configproperties-bug.git找到,以防有人想编译并运行以查看堆栈跟踪。

有没有人有收集@ConfigurationProperties的任何例子?通过简单地将声明的类型与Spring已经反序列化的实际类型进行匹配,我可以从中找到前进的方向,但这最终导致使用起来不方便。如果可能的话,我真的很想获得这个配置的最内层的值,如列表<>或数组类型,但我不知道如何。

回答

0

这里是你需要的东西:

不使用选项卡,使用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 
@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; 
    } 

} 

Apperantly,你不能使用在地图键里面,它只是剪掉了键,所以我删除了“Find .txt Files”键中的那个键。此外,spring-boot不支持映射内部的自动格式化数组,因此String []现在不可能,但列表正在工作。

+0

这并不能真正解决问题,但感谢您的尝试。 运行解决方案时,传递给setBase的事物的实际类型与声明的类型不同:它是同一问题的另一个示例。我认为可以说这个问题是“Spring的属性访问器无法看到过去的类型擦除”。列表以“0”,“1”,“2”等键作为LinkedHashMap 传递。换句话说,同样的问题。 –

+0

如果键包含一个点,则必须使用括号表示法,即'foo.items [two.bar] = 2'将设置'two.bar'键。 https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding –

+0

这个答案产生你所要求的:'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]}}'。请注意,yaml文件已更改为“目录列表”,而其他文件则更改为列表(' - ')而不是地图。 –