1. Overview
In this quick tutorial, we’ll learn 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 demonstrate how to bind YAML properties to a Map with a practical example.
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’re 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’ll focus on how to bind YAML properties into a bean class using the @ConfigurationProperties annotation*.*
First, we’ll 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
Then we’ll 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 static 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, we’ll 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, @V**alue allows us to directly inject 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
In this brief article, we discussed 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 this article is available over on GitHub.