2015-09-06 64 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文件已更改爲「目錄列表」,而其他文件則更改爲列表(' - ')而不是地圖。 –