Spring Boot @ConfigurationProperties example

Spring Boot @ConfigurationProperties

Spring Boot @ConfigurationProperties is letting developer maps the entire .properties and yml file into an object easily.

P.S Tested with Spring Boot 2.1.2.RELEASE

1. @Value

1.1 Normally, we use the @Value to inject the .properties value one by one, this is good for small and simple structure .properties files. For example,

global.properties

email=test@mkyong.com
thread-pool=12
GlobalProperties.java

@Component
@PropertySource("classpath:global.properties")
public class GlobalProperties {

    @Value("${thread-pool}")
    private int threadPool;

    @Value("${email}")
    private String email;
    
    //getters and setters

}

1.2 The equivalent in @ConfigurationProperties

GlobalProperties.java

import org.springframework.boot.context.properties.ConfigurationProperties;

@Component
@PropertySource("classpath:global.properties")
@ConfigurationProperties
public class GlobalProperties {

    private int threadPool;
    private String email;

    //getters and setters

}

2. @ConfigurationProperties

2.1 Review a complex structure .properties or yml file below, how we are going to map the values via @Value?

application.properties

#Logging
logging.level.org.springframework.web=ERROR
logging.level.com.mkyong=DEBUG

#Global
email=test@mkyong.com
thread-pool=10

#App
app.menus[0].title=Home
app.menus[0].name=Home
app.menus[0].path=/
app.menus[1].title=Login
app.menus[1].name=Login
app.menus[1].path=/login

app.compiler.timeout=5
app.compiler.output-folder=/temp/

app.error=/error/

or the equivalent in YAML.

application.yml

logging:
  level:
    org.springframework.web: ERROR
    com.mkyong: DEBUG
email: test@mkyong.com
thread-pool: 10
app:
  menus:
    - title: Home
      name: Home
      path: /
    - title: Login
      name: Login
      path: /login
  compiler:
    timeout: 5
    output-folder: /temp/
  error: /error/
Note
@ConfigurationProperties supports both .properties and .yml file.

2.2 @ConfigurationProperties comes to rescue :

AppProperties.java

package com.mkyong;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
@ConfigurationProperties("app") // prefix app, find app.* values
public class AppProperties {

    private String error;
    private List<Menu> menus = new ArrayList<>();
    private Compiler compiler = new Compiler();

    public static class Menu {
        private String name;
        private String path;
        private String title;

        //getters and setters

        @Override
        public String toString() {
            return "Menu{" +
                    "name='" + name + '\'' +
                    ", path='" + path + '\'' +
                    ", title='" + title + '\'' +
                    '}';
        }
    }

    public static class Compiler {
        private String timeout;
        private String outputFolder;

        //getters and setters

        @Override
        public String toString() {
            return "Compiler{" +
                    "timeout='" + timeout + '\'' +
                    ", outputFolder='" + outputFolder + '\'' +
                    '}';
        }

    }

    //getters and setters
}
GlobalProperties.java

package com.mkyong;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties // no prefix, find root level values.
public class GlobalProperties {

    private int threadPool;
    private String email;

	//getters and setters
}

3. @ConfigurationProperties Validation

This @ConfigurationProperties support JSR-303 bean validation.

3.1 Add @Validated on the @ConfigurationProperties class, and javax.validation annotations on the fields we want to validate.

GlobalProperties.java

package com.mkyong;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;

@Component
@ConfigurationProperties
@Validated
public class GlobalProperties {

    @Max(5)
    @Min(0)
    private int threadPool;

    @NotEmpty
    private String email;

    //getters and setters
}

3.2 Set thread-pool=10

application.properties

#Global
email=test@mkyong.com
thread-pool=10

3.3 Start Spring Boot and we will hits the following error message :

Console

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException: 
	Failed to bind properties under '' to com.mkyong.GlobalProperties failed:

    Property: .threadPool
    Value: 10
    Origin: class path resource [application.properties]:7:13
    Reason: must be less than or equal to 5


Action:

Update your application's configuration

4. DEMO


$ git clone https://github.com/mkyong/spring-boot.git
$ cd externalize-config-properties-yaml
$ mvn spring-boot:run

access localhost:8080
demo
Note
For more detail, please refer to this official Spring Boot Externalized Configuration

Download Source Code

$ git clone https://github.com/mkyong/spring-boot.git
$ cd externalize-config-properties-yaml
$ mvn spring-boot:run

access localhost:8080

References

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

avatar
15 Comment threads
6 Thread replies
1 Followers
 
Most reacted comment
Hottest comment thread
18 Comment authors
Minh HoangSudarshan K JAliciaMohammadDMM Recent comment authors
newest oldest most voted
Jeff
Guest
Jeff

Nice article! Just a simple question, when you are working with @ConfigurationProperties, the variable names must match the properties keys, right? What about names like “thread-pool” that you have used threadPool, it identify it automatically? Thanks!

mkyong
Guest
mkyong

yes, In Spring, this called relaxed binding
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-relaxed-binding

Both ‘thread-pool’ and ‘thread_pool’ will map to threadPool property.

Jeff
Guest
Jeff

Thank you! Really helps!

Minh Hoang
Guest
Minh Hoang

Nice article

Sudarshan K J
Guest
Sudarshan K J

Thanks for the ‘@Validated’ annotation for enabling field validation. Numerous other blogs have no mention of that.
Had been tirelessly trying to find just that for a couple of days now.

Alicia
Guest
Alicia

Great! In my way to start thinking with Spring boot this made me understand how to solve my problem in a very effective way!
Thank you

Mohammad
Guest
Mohammad

I noticed the pom file for this project has thymeleaf dependencies and the project name as Spring Boot Web Thymeleaf Example. I you could update your pom with the minor changes that would be cool. Thank you for all of your hard work.

DMM
Guest
DMM

Hi Mkyong,

I am looking for a example which I add properties to property file dynamically.
I meant that, Properties with proper formatted such as;

### App 2 properties
#——————————–
#Section 01
prop1 = value1
prop2 = value2
prop2 = value1

#Section 02
prop1 = value1
prop2 = value2
prop2 = value1

### App 3 properties
#——————————–
#Section 01
prop1 = value1
prop2 = value2
prop2 = value1

#Section 02
prop1 = value1
prop2 = value2
prop2 = value1

When I search in google. I have found that PropertiesConfigurationLayout class in Apache Commons.
https://commons.apache.org/proper/commons-configuration/userguide/howto_properties.html

Could you please give me an example for this.
Thank you and appreciate your effort.

Carol
Guest
Carol

Thanks

Pablo
Guest
Pablo

prefix not working. I have following in my java class:

@Component
@PropertySource(“classpath:custom-cas.properties”)
@ConfigurationProperties(prefix = “myprefix”)
public class CustomProperties {
//properties and getters/setters
}

and my custom-cas-properties file has:
myprefix.dummyValue=100
myprefix.isEnabled=True

but values are coming up null when I read them using
System.out.println(“Read dummyValue: “+ env.getProperty(“dummyValue”) );

If I remove the “myprefix” references i can read my properties.

What am I doing wrong?

Ansuman
Guest
Ansuman

@pablo If am not wrong, you can use either @PropertySource, where you have specify your file name or You can use @ConfigurationProperties(“custom”) this will search your file in your classpath .

peethanAbhilash
Guest
peethanAbhilash

Hi : Thanks, as usual your post are quite precise and informative.
One question – is there any way I can populate Spring-Config.xml parameter values from application properties ?

For eg : application.properties contains a value defined as “eas.ssl.ciphers=JKS”
and in config xml I need to apply as ${eas.ssl.ciphers}

Though in log I could see the application.properties are loaded as expected – it seems they are not applied within config.xml file as I get error no value found ?

Is this a valid case ?

Nitin
Guest
Nitin

Thanks for nice article Mkyong, but I have a question. I want to have some defaults in case properties are not mentioned in properties file. How can I get defaults along with @ConfigurationProperties. I was reading about @Value annotation which can provide defaults option, but these two are not mixing up together and I am getting error.

Igor
Guest
Igor

As of Spring Boot 1.5.4 (maybe even earlier) YML files are not processed correctly. They are parsed as regular properties files. In order to fix that: {code} public class YamlPropertySourceFactory implements PropertySourceFactory { @Override public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException { return name != null ? new PropertySourcesLoader().load(resource.getResource(), name, null) : new PropertySourcesLoader().load( resource.getResource(), getNameForResource(resource.getResource()), null); } private static String getNameForResource(Resource resource) { String name = resource.getDescription(); if (!StringUtils.hasText(name)) { name = resource.getClass().getSimpleName() + “@” + System.identityHashCode(resource); } return name; } } {code}

Igor
Guest
Igor

Add this factory class to your property source declaration:

e.g. @PropertySource(value = “classpath:yamlfile.yml”, factory = YamlPropertySourceFactory.class)

Doug
Guest
Doug

Thanks for this, very helpful. What would be the best approach to test a service that is injecting the class with the @ConfigurationProperties as a dependency? How should we go about to mock the properties?

Thien Nguyen
Guest
Thien Nguyen

How would you change this to use a config server instead of a properties file?

Shawn
Guest
Shawn

Hi Mkyong, when I use @ConfigurationProperties(prefix=”app”) with static @Bean getPropertyPlaceholderConfigurer(). it seems not working for mapping the keys in properties files, do you have any idea how to make this working? I am trying to load property files from a folder.

Chinnu Manju
Guest
Chinnu Manju

Thanks Mkyong for the nice article.
This really helped and made my work easier.
I also tried doing the same with Maps, map with String as Key and Menu as value. But that didnt work at all. I tried multiple things, but it didnt help. Could you please assist on how can I parse the yml values into a map with custom object?

Chinnu Manju
Guest
Chinnu Manju

@mkyong:disqus please help me with the above question. I am still stuck with this issue.

j3j3 Hype!!
Guest
j3j3 Hype!!

wahaha