June 21, 2022

Spring Boot Properties File: @ConfigurationProperties Example

If you are using some configuration parameters in your application then it is better to externalize your configuration rather than hard coding values. In Spring Boot one of the way to externalize your configuration is to use properties files or YAML files. In this post we’ll see how to use properties file in Spring Boot and how to read property values from properties file.

Spring Boot application.properties file

In Spring Boot, SpringApplication automatically loads properties from application.properties files and adds them to the Spring Environment. You should save application.properties file in one of the following locations.

  1. A /config subdirectory of the current directory
  2. The current directory
  3. A classpath /config package
  4. The classpath root

The list is ordered by precedence (properties defined in locations higher in the list override those defined in lower locations).

Note that you can also use YAML ('.yml') files as an alternative to '.properties'.

Creating application.properties file

Create application.properties file inside src/main/resources directory as the properties file should be in classpath.

Add some key-value pairs to application.properties file.

springboot.app.name=SpringBootProject
springboot.welcome.message=Welcome User

Using YAML file

You can also create an application.yml file instead of application.properties at the same location. YAML is a superset of JSON, it is a convenient format for specifying hierarchical configuration data.

Sample application.yml file

springboot:
	app:
		name:SpringBootProject
	welcome:
		message:Welcome User

Switching to another file name

If you want to name your configuration file as something other than application.properties you can do that by specifying a spring.config.name environment property.

java -jar SpringBootProject.jar --spring.config.name=myprops

You can also refer to an explicit location by using the spring.config.location environment property

java -jar SpringBootProject.jar --spring.config.location=classpath:/default.properties, classpath:/override.properties

Injecting configuration values using @Value annotation

Once you have your properties file ready you can use it in your Spring beans. One of the way to inject a property value from the properties is to use @Value annotation. Using @Value annotation you can read an environment variable or a system variable.

Here is a class where @Value annotation is used on the fields to inject property values by using the key of the properties.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class WelcomeConfiguration {
  @Value("${springboot.app.name}")
  private String name;
  @Value("${springboot.welcome.message}")
  private String message;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getMessage() {
    return message;
  }
  public void setMessage(String message) {
    this.message = message;
  }
}

You can test it using the following application class.

import org.netjs.SpringBootApp.controller.WelcomeConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootAppApplication  implements CommandLineRunner{
  @Autowired
  WelcomeConfiguration config;
  public static void main(String[] args) {
    SpringApplication.run(SpringBootAppApplication.class, args);
  }

  @Override
  public void run(String... args) throws Exception {
    // displaying property values
    System.out.println("Application Name- " + config.getName());
    System.out.println("Welcome Message- " + config.getMessage());
  }
}
Output
Application Name- SpringBootProject
Welcome Message- Welcome User

Application configuration using @ConfigurationProperties annotation

Using the @Value("${property}") annotation to inject configuration properties becomes tedious if you have multiple properties or your data is hierarchical in nature. Spring Boot provides a better alternative @ConfigurationProperties annotation to read configuration values from properties file.

To see how to use @ConfigurationProperties to read values from a properties file in Spring Boot application let’s create src/main/resources/application.properties file with values of different data types and also hierarchical in nature.

springboot.app.name=SpringBootProject
springboot.app.creator=knpcode
springboot.app.active=true
springboot.app.pages=4
#List
springboot.app.citycodes=US,IN,CN,AU

#-- Nested Properties--
springboot.app.inner.strproperty=test
#List
springboot.app.inner.datalist[0]=list0
springboot.app.inner.datalist[1]=list1
#Map
springboot.app.inner.propmap.key1=value1
springboot.app.inner.propmap.key2=value2
springboot.app.inner.propmap.key3=value3

Next is the class annotated with @ConfigurationProperties annotation which is an annotation for externalized configuration and binds some external Properties from a .properties or YAML file.

import java.util.List;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix="springboot.app")
public class WelcomeConfiguration {
  private String name;
  private String creator;
  private boolean active;
  private int pages;
  private List<String> cityCodes;
  private final Inner inner = new Inner();

  public static class Inner{
    private String strProperty;
    private List<String> dataList;
    private Map<String, String> propMap;
    
    public void setStrProperty(String strProperty) {
      this.strProperty = strProperty;
    }
    //.. getters and setters
  }
  public String getName() {
    return name;
  }
  public Inner getInner() {
    return inner;
  }
  //.. getters and setters
}

Some points to note here are-

  1. Using prefix element you can specify the properties that can be bound to the POJO. It can also take care of hierarchical properties (as done for static inner class in the example).
  2. Property value binding is done in type safe manner. As you can see in the POJO class there are fields of different types String, boolean, int, List, Map all of these fields are bound by converting properties to required types.
  3. Even if the keys in properties file are in all lower case those are correctly bound to their camel case counterparts in POJO class.
SpringBootApplication class

Using the following class you can display the bound properties.

import org.netjs.SpringBootApp.controller.WelcomeConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootAppApplication  implements CommandLineRunner{
  @Autowired
  WelcomeConfiguration config;
  public static void main(String[] args) {
    SpringApplication.run(SpringBootAppApplication.class, args);
  }

  @Override
  public void run(String... args) throws Exception {
    // displaying property values
    System.out.println("Application Name- " + config.getName());
    System.out.println("Creator- " + config.getCreator());
    System.out.println("Active- " + config.isActive());
    System.out.println("Pages- " + config.getPages());
    System.out.println("Codes- " + config.getCityCodes());
    
    System.out.println("Strporoperty- " + config.getInner().getStrProperty());
    System.out.println("Data List- " + config.getInner().getDataList());
    System.out.println("Prop Map- " + config.getInner().getPropMap());
  }
}
Output
Application Name- SpringBootProject
Creator- knpcode
Active- true
Pages- 4
Codes- [US, IN, CN, AU]
Strporoperty- test
Data List- [list0, list1]
Prop Map- {key1=value1, key2=value2, key3=value3}

@ConfigurationProperties Validation

Spring Boot attempts to validate @ConfigurationProperties classes whenever they are annotated with Spring’s @Validated annotation. JSR-303 javax.validation is supported and you can use JSR-303 javax.validation constraint annotations directly on your configuration class.

Add the spring-boot-starter-validation to get a compliant JSR-303 implementation on your classpath.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Add @Validated annotation and validation constraints on fields.

import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

@Component
@ConfigurationProperties(prefix="springboot.app")
@Validated
public class WelcomeConfiguration {
  @NotNull
  private String name;
  private String creator;
  private boolean active;
  private int pages;
  @NotEmpty
  private List<String> cityCodes;
  //it’s good practice to annotate the nested properties
  // associated field as @Valid
  @Valid
  private final Inner inner = new Inner();

  public static class Inner{
    @Size(min = 10, max = 20)
    private String strProperty;
    private List<String> dataList;
    private Map<String, String> propMap;
    //getters and setters
  }
  //getters and setters
}

Now if citycodes are removed from the application properties file and value for strProperty field is “test” (as per validation length of the value should be in range 10 to 20.) you should get the following error message.

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

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'springboot.app' to org.netjs.SpringBootApp.controller.WelcomeConfiguration failed:

    Property: springboot.app.inner.strProperty
    Value: test
    Reason: size must be between 10 and 20

    Property: springboot.app.cityCodes
    Value: []
    Reason: must not be empty


Action:

Update your application's configuration

That's all for the topic Spring Boot Properties File: @ConfigurationProperties Example. If something is missing or you have something to share about the topic please write a comment.


You may also like

No comments:

Post a Comment