Immutable @ConfigurationProperties Immutable @ConfigurationProperties java java

Immutable @ConfigurationProperties


From Spring Boot 2.2, it is at last possible to define an immutable class decorated with @ConfigurationProperties.
The documentation shows an example.
You just need to declare a constructor with the fields to bind (instead of the setter way) and to add the @ConstructorBinding annotation at the class level to indicate that constructor binding should be used.
So your actual code without any setter is now fine :

@ConstructorBinding@ConfigurationProperties(prefix = "example")public final class MyProps {  private final String neededProperty;  public MyProps(String neededProperty) {    this.neededProperty = neededProperty;  }  public String getNeededProperty() { .. }}


I have to resolve that problem very often and I use a bit different approach, which allows me to use final variables in a class.

First of all, I keep all my configuration in a single place (class), say, called ApplicationProperties. That class has @ConfigurationProperties annotation with a specific prefix. It is also listed in @EnableConfigurationProperties annotation against configuration class (or main class).

Then I provide my ApplicationProperties as a constructor argument and perform assignment to a final field inside a constructor.

Example:

Main class:

@SpringBootApplication@EnableConfigurationProperties(ApplicationProperties.class)public class Application {    public static void main(String... args) throws Exception {        SpringApplication.run(Application.class, args);    }}

ApplicationProperties class

@ConfigurationProperties(prefix = "myapp")public class ApplicationProperties {    private String someProperty;    // ... other properties and getters   public String getSomeProperty() {       return someProperty;   }}

And a class with final properties

@Servicepublic class SomeImplementation implements SomeInterface {    private final String someProperty;    @Autowired    public SomeImplementation(ApplicationProperties properties) {        this.someProperty = properties.getSomeProperty();    }    // ... other methods / properties }

I prefer this approach for many different reasons e.g. if I have to setup more properties in a constructor, my list of constructor arguments is not "huge" as I always have one argument (ApplicationProperties in my case); if there is a need to add more final properties, my constructor stays the same (only one argument) - that may reduce number of changes elsewhere etc.

I hope that will help


In the end, if you want an immutable object you can also "hack" the setter that is

@ConfigurationProperties(prefix = "myapp")public class ApplicationProperties {    private String someProperty;    // ... other properties and getters    public String getSomeProperty() {       return someProperty;    }    public String setSomeProperty(String someProperty) {      if (someProperty == null) {        this.someProperty = someProperty;      }           }}

Obviously if the property is not just a String, that is a mutable object, things are more complicated but that's another story.

Even better you can create a Configuration container

@ConfigurationProperties(prefix = "myapp")public class ApplicationProperties {   private final List<MyConfiguration> configurations  = new ArrayList<>();   public List<MyConfiguration> getConfigurations() {      return configurations   }}

where now the configuration is a clas without

public class MyConfiguration {    private String someProperty;    // ... other properties and getters    public String getSomeProperty() {       return someProperty;    }    public String setSomeProperty(String someProperty) {      if (this.someProperty == null) {        this.someProperty = someProperty;      }           }}

and application.yml as

myapp:  configurations:    - someProperty: one    - someProperty: two    - someProperty: other