Constructor Binding
The example in the previous section can be rewritten in an immutable fashion as shown in the following example:
-
Java
-
Kotlin
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConfigurationProperties("my.service")
public class MyProperties {
// fields...
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
// getters...
public boolean isEnabled() {
return this.enabled;
}
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
// fields...
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
// getters...
public String getUsername() {
return this.username;
}
public String getPassword() {
return this.password;
}
public List<String> getRoles() {
return this.roles;
}
}
}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import java.net.InetAddress
@ConfigurationProperties("my.service")
class MyProperties(val enabled: Boolean, val remoteAddress: InetAddress,
val security: Security) {
class Security(val username: String, val password: String,
@param:DefaultValue("USER") val roles: List<String>)
}
In this setup, the presence of a single parameterized constructor implies that constructor binding should be used.
This means that the binder will find a constructor with the parameters that you wish to have bound.
If your class has multiple constructors, the @ConstructorBinding
annotation can be used to specify which constructor to use for constructor binding.
To opt out of constructor binding for a class with a single parameterized constructor, the constructor must be annotated with @Autowired
.
Constructor binding can be used with records.
Unless your record has multiple constructors, there is no need to use @ConstructorBinding
.
Nested members of a constructor bound class (such as Security
in the example above) will also be bound through their constructor.
Default values can be specified using @DefaultValue
on constructor parameters and record components.
The conversion service will be applied to coerce the annotation’s String
value to the target type of a missing property.
Referring to the previous example, if no properties are bound to Security
, the MyProperties
instance will contain a null
value for security
.
To make it contain a non-null instance of Security
even when no properties are bound to it (when using Kotlin, this will require the username
and password
parameters of Security
to be declared as nullable as they do not have default values), use an empty @DefaultValue
annotation:
-
Java
-
Kotlin
public MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
class MyProperties(val enabled: Boolean, val remoteAddress: InetAddress,
@DefaultValue val security: Security) {
class Security(val username: String?, val password: String?,
@param:DefaultValue("USER") val roles: List<String>)
}
To use constructor binding the class must be enabled using @EnableConfigurationProperties or configuration property scanning.
You cannot use constructor binding with beans that are created by the regular Spring mechanisms (for example @Component beans, beans created by using @Bean methods or beans loaded by using @Import )
|
To use constructor binding in a native image the class must be compiled with -parameters .
This will happen automatically if you use Spring Boot’s Gradle plugin or if you use Maven and spring-boot-starter-parent .
|
The use of java.util.Optional with @ConfigurationProperties is not recommended as it is primarily intended for use as a return type.
As such, it is not well-suited to configuration property injection.
For consistency with properties of other types, if you do declare an Optional property and it has no value, null rather than an empty Optional will be bound.
|