Spring boot yml property file processing [duplicate] - spring-boot

I have a following yml config:
foo:
bar.com:
a: b
baz.com:
a: c
With a following class Spring tries to inject map with keys 'bar' and 'baz', treating dots as separator:
public class JavaBean {
private Map<String, AnotherBean> foo;
(...)
}
I have tried quoting the key (i.e. 'bar.com' or "bar.com") but to no avail - still the same problem. Is there a way around this?

A slight revision of #fivetenwill's answer, which works for me on Spring Boot 1.4.3.RELEASE:
foo:
"[bar.com]":
a: b
"[baz.com]":
a: c
You need the brackets to be inside quotes, otherwise the YAML parser basically discards them before they get to Spring, and they don't make it into the property name.

This should work:
foo:
"[bar.com]":
a: b
"[baz.com]":
a: c
Inspired from Spring Boot Configuration Binding Wiki

This is not possible if you want automatic mapping of yaml keys to Java bean attributes. Reason being, Spring first convert YAML into properties format.
See section 24.6.1 of link below:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
So, your YAML is converted to:
foo.bar.com.a=b
foo.baz.com.a=c
Above keys are parsed as standard properties.
As a work around, you can use Spring's YamlMapFactoryBean to create a Yaml Map as it is. Then, you can use that map to create Java beans by your own.
#Configuration
public class Config {
private Map<String, Object> foo;
#Bean
public Map<String, Object> setup() {
foo = yamlFactory().getObject();
System.out.println(foo); //Prints {foo={bar.com={a=b}, baz.com={a=c}}}
return foo;
}
#Bean
public YamlMapFactoryBean yamlFactory() {
YamlMapFactoryBean factory = new YamlMapFactoryBean();
factory.setResources(resource());
return factory;
}
public Resource resource() {
return new ClassPathResource("a.yaml"); //a.yaml contains your yaml config in question
}
}

Related

Spring does not load Map of objects from YAML, if the key String contains dots [duplicate]

I have a following yml config:
foo:
bar.com:
a: b
baz.com:
a: c
With a following class Spring tries to inject map with keys 'bar' and 'baz', treating dots as separator:
public class JavaBean {
private Map<String, AnotherBean> foo;
(...)
}
I have tried quoting the key (i.e. 'bar.com' or "bar.com") but to no avail - still the same problem. Is there a way around this?
A slight revision of #fivetenwill's answer, which works for me on Spring Boot 1.4.3.RELEASE:
foo:
"[bar.com]":
a: b
"[baz.com]":
a: c
You need the brackets to be inside quotes, otherwise the YAML parser basically discards them before they get to Spring, and they don't make it into the property name.
This should work:
foo:
"[bar.com]":
a: b
"[baz.com]":
a: c
Inspired from Spring Boot Configuration Binding Wiki
This is not possible if you want automatic mapping of yaml keys to Java bean attributes. Reason being, Spring first convert YAML into properties format.
See section 24.6.1 of link below:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
So, your YAML is converted to:
foo.bar.com.a=b
foo.baz.com.a=c
Above keys are parsed as standard properties.
As a work around, you can use Spring's YamlMapFactoryBean to create a Yaml Map as it is. Then, you can use that map to create Java beans by your own.
#Configuration
public class Config {
private Map<String, Object> foo;
#Bean
public Map<String, Object> setup() {
foo = yamlFactory().getObject();
System.out.println(foo); //Prints {foo={bar.com={a=b}, baz.com={a=c}}}
return foo;
}
#Bean
public YamlMapFactoryBean yamlFactory() {
YamlMapFactoryBean factory = new YamlMapFactoryBean();
factory.setResources(resource());
return factory;
}
public Resource resource() {
return new ClassPathResource("a.yaml"); //a.yaml contains your yaml config in question
}
}

Spring boot key, value properties file

Hi Is there a simple way using spring boot to load in a key, value properties file. I can do it the old way using the Properties class but wanted to check if this can be easily done with spring boot (still new to this)
Thanks,
Example
A = Apple
B = Banana
etc
Yes. If you place a file named application.properties into src/main/resources/ you can inject its values like so:
application.properties
foo=bar
Foo.class
#Component
public class Foo {
#Value("${foo}")
String foo; //equals 'bar'
//.......//
}
Alternatively you can look up properties programmatically
#SpringBootApplication
public class PropertyLookupApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(PropertyLookupApplication.class, args);
String foo = context.getEnvironment().getProperty("foo"); //equals 'bar'
}
}
Update
If you want application.properties as a Map then you can make sure of Spring's PropertiesLoaderUtils utility class:
Resource resource = new ClassPathResource("application.properties");
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
That returns a standard java.util.Properties object which is a Map.

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.
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}
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 ;-)

What's the best way to load a yaml file to Map(not an environment configuration file) in spring boot web project?

In my data framework layer, I'd like to read an yaml from src/main/resources.
The file name is mapconfigure.yaml. It's associated with the business data, not just environment configuration data.
Its content's like:
person1:
name: aaa
addresses:
na: jiang
sb: su
person2:
name: bbb
addresses:
to: jiang
bit: su
I want to store this information into a HashMap.
Does it mean to use some spring annotation like #ConfigurationProperties?
How to achieve this in details?
In addition, I can't change the file name. It means I have to use mapconfigure.yaml as the file name, not application.yml or application.properties.
The structure of my HashMap is as follows:
HashMap<String, Setting>
#Data
public class Setting{
private String name;
private HashMap<String, String> addresses
}
My expected HashMap's as follows:
{person1={name=aaa, addresses={na=jiang, sb=su}}, person2={name=bbb, addresses={to=jiang, bit=su}}}
I'm not sure if I can use YamlMapFactoryBean class to do this.
The return type of the getObject method in YamlMapFactoryBean class is Map<String, Object>, not a generic type, like Map<String, T>.
Spring boot doc just said
Spring Framework provides two convenient classes that can be used to load YAML documents. The YamlPropertiesFactoryBean will load YAML as Properties and the YamlMapFactoryBean will load YAML as a Map.
But there isn't a detailed example.
UPDATE:
In github, I created a sample. It's Here.
In this sample, I want to load myconfig.yaml to theMapProperties object in SamplePropertyLoadingTest class. Spring boot version is 1.5.1, so I can't use location attribute of #ConfigurationProperties.
How to do this?
You can indeed achieve this with #ConfigurationProperties.
From Spring Boot 1.5.x onwards (lack of #ConfigurationProperies locations attr.):
new SpringApplicationBuilder(Application.class)
.properties("spring.config.name=application,your-filename")
.run(args);
#Component
#ConfigurationProperties
public class TheProperties {
private Map<String, Person> people;
// getters and setters are omitted for brevity
}
In Spring Boot 1.3.x:
#Component
#ConfigurationProperties(locations = "classpath:your-filename.yml")
public class TheProperties {
private Map<String, Person> people;
// getters and setters are omitted for brevity
}
The Person class for above examples looks like this:
public class Person {
private String name;
private Map<String, String> addresses;
// getters and setters are omitted for brevity
}
I have tested the code with the following file: your-filename.yml
defined in src/main/resources, the contents:
people:
person1:
name: "aaa"
addresses:
na: "jiang"
sb: "su"
person2:
name: "bbb"
addresses:
to: "jiang"
bit: "su"
Please let me know if you need any further assistance.
try this
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
try {
PropertySource<?> applicationYamlPropertySource = loader.load(
"properties", new ClassPathResource("application.yml"), null);// null indicated common properties for all profiles.
Map source = ((MapPropertySource) applicationYamlPropertySource).getSource();
Properties properties = new Properties();
properties.putAll(source);
return properties;
} catch (IOException e) {
LOG.error("application.yml file cannot be found.");
}

Escaping a dot in a Map key in Yaml in Spring Boot

I have a following yml config:
foo:
bar.com:
a: b
baz.com:
a: c
With a following class Spring tries to inject map with keys 'bar' and 'baz', treating dots as separator:
public class JavaBean {
private Map<String, AnotherBean> foo;
(...)
}
I have tried quoting the key (i.e. 'bar.com' or "bar.com") but to no avail - still the same problem. Is there a way around this?
A slight revision of #fivetenwill's answer, which works for me on Spring Boot 1.4.3.RELEASE:
foo:
"[bar.com]":
a: b
"[baz.com]":
a: c
You need the brackets to be inside quotes, otherwise the YAML parser basically discards them before they get to Spring, and they don't make it into the property name.
This should work:
foo:
"[bar.com]":
a: b
"[baz.com]":
a: c
Inspired from Spring Boot Configuration Binding Wiki
This is not possible if you want automatic mapping of yaml keys to Java bean attributes. Reason being, Spring first convert YAML into properties format.
See section 24.6.1 of link below:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
So, your YAML is converted to:
foo.bar.com.a=b
foo.baz.com.a=c
Above keys are parsed as standard properties.
As a work around, you can use Spring's YamlMapFactoryBean to create a Yaml Map as it is. Then, you can use that map to create Java beans by your own.
#Configuration
public class Config {
private Map<String, Object> foo;
#Bean
public Map<String, Object> setup() {
foo = yamlFactory().getObject();
System.out.println(foo); //Prints {foo={bar.com={a=b}, baz.com={a=c}}}
return foo;
}
#Bean
public YamlMapFactoryBean yamlFactory() {
YamlMapFactoryBean factory = new YamlMapFactoryBean();
factory.setResources(resource());
return factory;
}
public Resource resource() {
return new ClassPathResource("a.yaml"); //a.yaml contains your yaml config in question
}
}

Resources