7

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?

niaomingjian
  • 3,472
  • 8
  • 43
  • 78
  • 1
    @niamingjian, please use this below link which will help you on how to externalize the configuration. https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html – Praveen Kumar K S Mar 29 '17 at 12:02
  • You want to store this information into a HashMap. Do you want that as a key or as a value. What would be the value if you want it as key, and what would be the key if you want to load the data into a HashMap value? – Anthon Mar 29 '17 at 13:08
  • @Anthon I added my expected Map. – niaomingjian Mar 29 '17 at 13:32
  • @niaomingjian That is what you should get if you load the YAML, as the toplevel is a mapping, so there is no need to store this anywhere, just load it. – Anthon Mar 29 '17 at 13:54
  • @Anthon The problem is how to load it. I don't know. – niaomingjian Mar 30 '17 at 01:02

2 Answers2

7

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.

kris_k
  • 341
  • 2
  • 10
  • There're two problems. First, I'm using springboot1.5.1 and in this version the `locations` attribute of `@ConfigurationProperties` has been moved.Second, There isn't `people:` element in my file. – niaomingjian Mar 30 '17 at 01:00
  • If it comes to the 1st problem (lack of locations attribute in spring boot 1.5.x) you can adjust spring.config.name property ( https://github.com/spring-projects/spring-boot/issues/6220#issuecomment-228412077 ). Regarding the 2nd problem can you modify mapconfigure.yaml in any way? Can't you add a prefix like: people (the name is irrelevant, it should simply correspond to the Map name in Java code)? – kris_k Mar 31 '17 at 21:01
  • On the other hand if data in mapconfigure.yaml is strictly business data, ConfigurationProperties might not be the best option. In the question you have mentioned YamlMapFactoryBean. In the accepted answer of http://stackoverflow.com/questions/34070987/escaping-a-dot-in-a-map-key-in-yaml-in-spring-boot there is an example of YamlMapFactoryBean usage. – kris_k Mar 31 '17 at 22:23
  • Thank you very much. I added a prefix `people` in yaml file and added `spring.config.location` property in environment variables to define my custom file. If I used `YamlMapFactoryBean`, would I get a `generic Map` like `Map`? – niaomingjian Apr 01 '17 at 01:51
  • When using YamlMapFactoryBean you will not get generic Map. It returns Map, and the value stored in a Map is in fact a Map as well. To get Map you would have to write some custom code responsible for conversion from Map to Map – kris_k Apr 01 '17 at 09:18
  • Thank you a lot. Now I plan to use `spring.config.location` to configure. If adding it to `OS environment variable`, the program runs well. Where else can I configure it inside the program, like `new SpringApplicationBuilder(Application.class).properties("spring.config.name=application,your-filename").run(args);` – niaomingjian Apr 07 '17 at 01:51
  • In fact, I'd like to read `yaml` file in my `Junit Test class`. In the `main` class, I found the configuration works. In Junit Test class, how should I configure it? – niaomingjian Apr 07 '17 at 02:48
  • If you want to prepare Integration or E2E tests you can use @SpringBootTest annotation on your test class and specify which classes are used to load ApplicationContext. After that you can simply autowire the properties and use them in scope of your tests. – kris_k May 02 '17 at 13:51
  • any updtes after this 1.5.x versions?? Like in 2.0?? – Anand Varkey Philips May 05 '18 at 07:15
  • 1
    Mentioned solution works in Spring Boot 2.0.x as well. – kris_k Aug 20 '18 at 18:13
2

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.");
        }
pvpkiran
  • 25,582
  • 8
  • 87
  • 134