Using @ConfigurationProperties in Spring Boot

Examples of reading and mapping external configurations from a properties or yaml file to a Java Bean in Spring Boot applications.

Overview

With Spring Boot we can easily externalize application level configurations to a properties or yaml file. Moreover, Spring Boot also provides excellent support for automatically reading this configurations and mapping them into a dedicated Java Bean instance.

In this tutorial we’ll learn about mapping the properties file or yaml file into Java Bean using @ConfigurationProperties annotation.

@ConfigurationProperties Annotation

The @ConfigurationPropertis annotation is used on a class or a @Bean method to map external properties configurations into the class or bean.

The binding between the properties and the bean fields happen based on the setter methods in the java bean class. In order to use constructors for such bindings, we can additionally use @ConstructorBinding annotation.

@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ConfigurationProperties { @AliasFor("prefix") String value() default ""; @AliasFor("value") String prefix() default ""; boolean ignoreInvalidFields() default false; boolean ignoreUnknownFields() default true; }
Code language: Java (java)

Attributes:

  • prefix: When properties are grouped under a common prefix, we can use the prefix attribute to load only the subset of the properties.
  • ignoreInvalidFields: It is false by default, but we can set to true if we want data type mismatch errors should be ignored.
  • ignoreUnknownFields: Unknown fields are the fields in properties file which does not have respective field in the Java Bean. By default Spring ignores such cases, however we can set this attribute to false and let it throw error.

Reading Simple Properties

Consider we have a simple set of properties in a yaml or a properties file. Each of the properties field denote a different configuration. We are using yaml in our examples, but everything works the same even if you use properties files instead.

application.yaml

default-username: default_user default-password: password_default connection-timeout: 2000
Code language: YAML (yaml)

We want to read and use these properties in our application. In order to do that, we will create a class to hold these properties.

@Configuration @ConfigurationProperties public class SimpleProperties { private String defaultUsername; private String defaultPassword; private int connectionTimeout; // Constructor, Getter, and Setter methods @Override public String toString() { return "defaultUsername: " + defaultUsername + ",\ndefaultPassword: " + defaultPassword + ",\nconnectionTimeout" + connectionTimeout; } }
Code language: Java (java)

Note a few things here,

  • Our class is marked @Configuration. This is for spring boot to find this class during scanning.
  • Field names are in standard Java camel case, while the properties are in kebab case. However, it automatically binds fields appearing in different cases, e.g. UPPER_CASE, kebab-case, camelCase, or underscore_notation.
  • Although, we have provided a constructor, getter and setter methods, only setter methods are required for the binding.

Let’s print the Java bean upon startup, for example using a @PostConstruct method.

* Simple Properties: 
defaultUsername: default_user,
defaultPassword: password_default,
connectionTimeout: 2000

The output shows, all the properties fields are mapped correctly into the Java class.

Reading Properties using Prefix

Sometimes we can organize properties into different groups. This is done by using a prefix that helps identify a particular group.

For example, next is an application.yaml file that

login-service: login-url: https://login.example.com username: login_user password: password123 user-service: url: https://users.example.com username: user_name password: strong-password
Code language: YAML (yaml)

Putting properties into groups makes them easily readable and manageable. In addition using @ConfigurationProperties we can read properties from a specific group or load different properties groups in different Java beans using prefix attribute.

We will create different properties classes to load properties based on their prefix. First, let’s create a Login Service Properties class.

@Configuration @ConfigurationProperties(prefix = "login-service") public class LoginServiceProperties { private String loginUrl; private String username; private String password; // Constructor, Getter, and Setter methods @Override public String toString() { return "loginUrl: " + loginUrl + ",\nusername: " + username + ",\npassword: " + password; } }
Code language: Java (java)

Next, create User Service Properties class.

@Configuration @ConfigurationProperties(prefix = "user-service") public class UserServiceProperties { private String url; private String username; private String password; // Constructor, Getter, and Setter methods @Override public String toString() { return "url: " + url + ",\nusername: " + username + ",\npassword: " + password; } }
Code language: Java (java)

Note that, in both of the above classes we have used @ConfiguratonProperties annotation with different prefix values. Having that, spring will load particular subset of the properties into the respective classes.

Let’s use a @PostConstruct based method to print both of the instances on the console.

* Login Service Properties: 
loginUrl: https://login.example.com,
username: login_user,
password: password123
* User Service Properties
url: https://users.example.com,
username: user_name,
password: strong-password

We can see both of the properties instances have received respective properties configurations.

Reading Properties with Setter Methods

Spring @ConfigurationProperties, by default uses setter methods to set individual properties on the Java bean. In order to demonstrate that we will load the login-service properties again in a separate Java bean. However, this time we will provide a zero argument – default constructor and setter methods.

@Configuration @ConfigurationProperties(prefix = "login-service") public class SetterBasedLoginProperties { private String loginUrl; private String username; private String password; public SetterBasedLoginProperties(){} public void setLoginUrl(String loginUrl) { this.loginUrl = loginUrl; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } // ToString() method }
Code language: Java (java)

So, we have provided a default constructor and only the setter methods. As the class uses prefix = login-service it will load the particular subset of properties that we saw in the preceding example.

* Setter Based Properties
loginUrl: https://login.example.com,
username: login_user,
password: password123

Upon printing the populated Java bean, we can see all the properties are correctly bound.

Binding Properties with Different Names

Having Setter methods based properties binding, the @ConfigurationProperties allows us to bind fields that do not match exactly.

For example, we want to bind a properties or yaml file field to a Java bean field but their names are different.

login-service: login-url: https://login.example.com
Code language: YAML (yaml)

From the previously seen examples, we have login-url property under login-service prefix. However, the respective Java bean has a url field

private String url;
Code language: Java (java)

By default, Spring @ConfigurationProperties won’t bind the login-url value in the url field of Java bean. In order to overcome that problem, we can provide a dummy setter method that matches the properties field name pattern.

@Configuration @ConfigurationProperties(prefix = "login-service") public class DifferentlyNamedProperties { private String url; public void setLoginUrl(String loginUrl) { this.url = loginUrl; } @Override public String toString() { return "url: " + url; } }
Code language: Java (java)

Make a note that, we have provided a dummy setter method, which is setting value on the url variable. When binding the properties values, Spring uses their name patterns to locate appropriate setter method. That means, it doesn’t care about the actual name of the Java class field.

Let’s start the application, and print the populated Properties class.

* DifferentlyNamedProperties
url: https://login.example.com

That proves that we can provide a dummy setter method to map properties with different names.

Reading Properties with Constructor

As we have seen mapping properties or yaml file fields using Setter methods is simple and straightforward. However, having the Setter methods in a properties class makes it mutable. As the properties configurations are constants, we may want to make the application properties class to be immutable.

To make the application properties class immutable, we can get rid of the setter methods and use Constructor based properties binding in Spring. To do so, we need to use @ConstructorBinding annotation on our @ConfigurationProperties bean.

@ConstructorBinding @ConfigurationProperties(prefix = "login-service") public class ConstructorBasedLoginProperties { private String loginUrl; private String username; private String password; public ConstructorBasedLoginProperties( String loginUrl, String username, String password) { this.loginUrl = loginUrl; this.username = username; this.password = password; } // Getter Methods // toString() method }
Code language: Java (java)

Note that our properties class has an all-argument constructor, which is the only constructor, and no setter methods.

Having @ConstructorBinding annotation, Spring loads the properties configurations using the provided constructor. Also, without any setter methods the state of the created instance cannot be modified. Thus, it is immutable in behaviour.

The only thing to note here is, in order to use @ConstructorBinding the Configuration properties needs to be enabled explicitly. This is done by using @EnableConfigurationProperties or @ConfigurationPropertiesScan annotation in Application class or on a @Configuration class.

Summary

With this tutorial, we explored the @ConfigurationProperties annotation in Spring. We learned that, using @ConfigurationProperties in Spring Boot, we can read and bind application level properties file or yaml file configurations into a Java bean.

Spring uses relaxed mapping strategy to match properties field names with the java class field names. Thus the properties or yaml file fields can exist in UPPER_CASE, kebab-case, camelCase, or underscore_notation.

Then we explored ways of mapping simple properties that have a flat structure, or using prefix attribute to bind properties subsets based on a common prefix. While doing so, we understood that Spring uses Setter methods to inject the configurations in Java class. However, we can use @ConstructorBinding annotation to use constructor for properties injection. Doing so, we can make our application properties class immutable.

For the full source code of the examples used in this tutorial, you can refer to our Github Repository.