user2337270
user2337270

Reputation: 1243

Preventing Spring Boot from creating nested map from dot-separated key in application.yml?

I have a problem with Spring Boot creating a nested map from a dot-separated key. It's essentially the same problem that is described here, but the solution suggested there doesn't work for me. I'm using Spring Boot 1.5.3.RELEASE in case it matters. My applications.yml file contains this:

props:
  webdriver.chrome.driver: chromedriver

My config class:

@Configuration
@EnableConfigurationProperties
public class SpringConfig {
  private Map<String, String> props = new HashMap<>();

  @ConfigurationProperties(prefix = "props")
  public void setProps(Map<String, String> props) {
    this.props = props;
  }

  @ConfigurationProperties(prefix = "props")
  @Bean(destroyMethod="", name = "props")
  public Map<String, String> getProps() {
    return props;
  }
}

Unfortunately, after Spring Boot processes the YAML file, the dot separated key gets split up into sub-maps. The result from callig getProps() and printing the result to System.out looks like this:

{webdriver={chrome={driver=chromedriver}}}

I've tried changing the type of the props field to Properties, Map<String, Object> etc, but nothing seems to make any difference. I haven't found any way of manipulating the parsing behavior to accomplish what I want. Any help is much appreciated. I've spent so much time on this, that I'll go blind if I look at the code any further.

Upvotes: 2

Views: 2751

Answers (2)

user2337270
user2337270

Reputation: 1243

After much experimenting, this seemed to work:

@Configuration
@EnableAutoConfiguration
@EnableConfigurationProperties
@ConfigurationProperties
public class SpringConfig {
    private Properties info = new Properties();

    public Properties getProps() {
        return info;
    }
  }
}

But I had to put single quotes around the YAML entry, otherwise Spring Boot would make the property nested:

props:
  'webdriver.chrome.driver': chromedriver
  'foo.bar.baz': foobarbaz

A couple of things I noticed. The getter for the Properties (getProps() in this case) must be declared public, and it has to match the property key that you're trying to bind in the YAML. I.e. since the key is 'props', the getter has to be called getProps(). I guess it's logical, and documented somewhere, but that had slipped me by somehow. I thought by using the prefix="foobar" on the @ConfigurationProperties annotation, that wasn't the case, but it seems to be. I guess I should RTFM ;-)

Upvotes: 2

Mohankumar Rathinam
Mohankumar Rathinam

Reputation: 633

Try using YamlMapFactoryBean this will load YAML as MAP.

@Bean
public YamlMapFactoryBean yamlFactory() {
    YamlMapFactoryBean factory = new YamlMapFactoryBean();
    factory.setResources(resource());
    return factory;
}

public Resource resource() {
    return new ClassPathResource("application.yml");
}

public Map<String, String> getProps() {
   props = yamlFactory().getObject();
 return props;
}

The output looks

props{webdriver.chrome.driver=chromedriver}

Upvotes: 2

Related Questions