Quantcast
Channel: Baeldung
Viewing all articles
Browse latest Browse all 4535

Inject a Map from a YAML File with Spring

$
0
0

1. Overview

In this quick tutorial, we're going to take a close look at how to inject a map from a YAML file in Spring Boot.

First, we'll start with a little bit of insight on YAML files in Spring Framework. Then, we'll showcase, through a practical example, how to bind YAML properties to a Map.

2. YAML Files in Spring Framework

Using YAML files to store external configuration data is a common practice among Spring developers. Basically, Spring supports YAML documents as an alternative to properties and uses SnakeYAML under the hood to parse them.

Without further ado, let’s see what a typical YAML file looks like:

server:
  port: 8090
  application:
    name: myapplication
    url: http://myapplication.com

As we can see, the YAML file is self-explanatory and more human-readable. As a matter of fact, YAML provides a fancy and concise way to store hierarchical configuration data.

By default, Spring Boot reads configuration properties from application.properties or application.yml at application startup. However, we can use @PropertySource to load a custom YAML file.

Now that we are familiar with what a YAML file is, let's see how to inject YAML properties as a Map in Spring Boot.

3. How to Inject a Map from a YAML File

Spring Boot has taken data externalization to the next level by providing a handy annotation called @ConfigurationProperties. This annotation is introduced to easily inject external properties from configuration files directly into Java objects.

In this section, we're going to cover in-depth how to bind YAML properties into a bean class using the @ConfigurationProperties annotation.

First, let's define some key-value properties in application.yml:

server:
  application:
    name: InjectMapFromYAML
    url: http://injectmapfromyaml.dev
    description: How To Inject a map from a YAML File in Spring Boot
  config:
    ips:
      - 10.10.10.10
      - 10.10.10.11
      - 10.10.10.12
      - 10.10.10.13
    filesystem:
      - /dev/root
      - /dev/md2
      - /dev/md4
  users: 
    root:
      username: root
      password: rootpass
    guest:
      username: guest
      password: guestpass

In this example, we'll try to map application into a simple Map<String, String>. Similarly, we'll inject config details as a Map<String, List<String>>, and users as a Map with String keys and objects belonging to a user-defined class – Credential – as values.

Second, let's create a bean class – ServerProperties – to encapsulate the logic of binding our configuration properties to Maps:

@Component
@ConfigurationProperties(prefix = "server")
public class ServerProperties {

    private Map<String, String> application;
    private Map<String, List<String>> config;
    private Map<String, Credential> users;

    // getters and setters

    public class Credential {
    	
        private String username;
        private String password;
        
        // getters and setters
        
    }
}

As we can see, we decorated the ServerProperties class with @ConfigurationProperties. That way, we tell Spring to map all the properties with the specified prefix to an object of ServerProperties.

Recall that our app needs to be enabled for configuration properties as well, though this is done automatically in most Spring Boot applications.

Finally, let's test if our YAML properties are properly injected as Maps:

@RunWith(SpringRunner.class)
@SpringBootTest
class MapFromYamlIntegrationTest {

    @Autowired
    private ServerProperties serverProperties;

    @Test
    public void whenYamlFileProvidedThenInjectSimpleMap() {
        assertThat(serverProperties.getApplication())
          .containsOnlyKeys("name", "url", "description");

        assertThat(serverProperties.getApplication()
          .get("name")).isEqualTo("InjectMapFromYAML");
    }

    @Test
    public void whenYamlFileProvidedThenInjectComplexMap() {
        assertThat(serverProperties.getConfig()).hasSize(2);

        assertThat(serverProperties.getConfig()
          .get("ips")
          .get(0)).isEqualTo("10.10.10.10");

        assertThat(serverProperties.getUsers()
          .get("root")
          .getUsername()).isEqualTo("root");
    }

}

4. @ConfigurationProperties vs @Value

Now let's do a quick comparison of @ConfigurationProperties and @Value.

Despite the fact that both annotations can be used to inject properties from configuration files, they are quite different. The major difference between these two annotations is that each one serves a different purpose.

In short, @Value allows us to inject directly a particular property value by its key. However, @ConfigurationProperties annotation binds multiple properties to a particular object and provides access to the properties through the mapped object.

In general, Spring recommends using @ConfigurationProperties over @Value when it comes to injecting configuration data. @ConfigurationProperties offers a great way to centralize and group configuration properties in a structured object that we can inject later into other beans.

5. Conclusion

To sum it up, we first explained how to inject a Map from a YAML file in Spring Boot. Then, we highlighted the difference between @ConfigurationProperties and @Value.

As usual, the complete source code for the article is available over on GitHub.


Viewing all articles
Browse latest Browse all 4535

Trending Articles