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}"
To work with @ConfigurationProperties beans, you can inject them in the same way as any other bean, as shown in the following example: @Service public class MyService { private final AcmeProperties properties; @Autowired public MyService(AcmeProperties properties) { this. properties = properties; } //...
As of Spring 4.3, classes with a single constructor can omit the @Autowired annotation. This is a nice little bit of convenience and boilerplate removal. On top of that, also starting with 4.3, we can leverage the constructor-based injection in @Configuration annotated classes.
Constructor injection (from the definition) does not allow you to create circular dependencies between beans. This limitation is actually an advantage of constructor injection - Spring can resolve circular dependencies when setter injection is used without you even noticing.
If we use both constructor and setter injection, IOC container will use the setter injection. Changes: We can easily change the value by setter injection. It doesn't create a new bean instance always like constructor. So setter injection is flexible than constructor injection.
is possible with spring boot since version 2.2.0 documentation is here: Constructor binding adding the new annotation @ConstructorBinding.
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With