Use constructor injection for spring ConfigurationProperties subclasses

Arthur :

I was looking at this https://www.baeldung.com/configuration-properties-in-spring-boot and was wondering if it was possible to use constructor injection for these in order to enforce some immutability properties.

For example would it be possible to do this:

@Component
@ConfigurationProperties("my-config")
public class MyConfig {

    private final List<String> values;

    public MyConfig(@Value("${values}") List<String> values) {
        this.values = ImmutableList.copyOf(values);
    }
}

And then in my yml config have

my-config.values:
  - foo
  - bar

But I get this error:

java.lang.IllegalArgumentException: Could not resolve placeholder 'values' in string value "${values}"
davidxxx :

The documentation states :

Property values can be injected directly into your beans by using the @Value annotation, accessed through Spring’s Environment abstraction, or be bound to structured objects through @ConfigurationProperties. :

You actually try to mix their behavior.
values is not a property of the Spring environment but my-config.values is.
Even declared inside MyConfig such as @Value("${values})" it doesn't change anything as @ConfigurationProperties bounds the properties to a structured object. And of course it doesn't create new properties in the Spring environment, that is where @Value() looks for to resolve the value expression.
Whereas the exception to resolve ${values}.

As MyConfig is a component @Value should be what you need :

@Component
public class MyConfig {

    private final List<String> values;

    public MyConfig(@Value("${my-config.values}") List<String> values) {
        this.values = ImmutableList.copyOf(values);
    }
}

You could also prevent the mutability by protecting the setter with a check but this will detect the issue only at runtime :

@ConfigurationProperties("my-config")
public class MyConfig {

    private final List<String> values;

    public List<String> getValue(){
         return values;
    }
    public void setValue(List<String> values){  
         if (this.values != null){
             throw new IllegalArgumentException("...");
         }                    
         this.values = ImmutableList.copyOf(values);
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=80399&siteId=1