Hi, if I understood #5110 correctly then one should expect optional configuration properties to be assigned.
Find a sample application prepared here: https://github.com/mamachanko/optional-nested-configuration-property
Assuming a config classes like so:
@Component
@ConfigurationProperties(prefix = "config")
@Data
@Validated
class Config {
@NotBlank
private String requiredProperty;
private Optional<String> optionalProperty = Optional.empty();
@NotNull
private MoreConfig moreRequiredConfig;
private Optional<MoreConfig> moreOptionalConfig = Optional.empty();
}
@Data
class MoreConfig {
private String property;
}
Running w/ full configuration
spring:
profiles: full
config:
required-property: this-is-required
optional-property: this-is-optional
more-required-config:
property: this-is-required
more-optional-config:
property: this-is-optional
$ ./mvnw clean spring-boot:run -Dspring.profiles.active=full
...
2019-02-19 21:08:16.288 INFO 28484 --- [main] i.g.m.o.ConfigLogger: Config(requiredProperty=this-is-required, optionalProperty=Optional[this-is-optional], moreRequiredConfig=MoreConfig(property=this-is-required), moreOptionalConfig=Optional.empty)
- The field
optionalPropertyof typeOptional<String>gets assigned as expected. - The field
moreOptionalConfigof typeOptional<MoreConfig>remainsOptional.empty. This is not expected. It is expected to beMoreConfig(property=this-is-optional).
Does that make sense?
Comment From: philwebb
Binding to Optional fields currently only works with values that the ConversionService creates, it doesn't work with nested configuration properties and I'm personally not a big fan of using Optional with in fields (see this stackoverflow answer for details of why).
It's possible that we might be able to update the binder to fully support Optional but I'm interested in why you're keen to use it with nested configurations. It feels like it might make properties much harder to access, especially if the nested configurations themselves have optional values. Consider:
if(config.getMoreOptionalConfig().isPresent()) {
String value = config.getMoreOptionalConfig().get().getSomeNestedProperty().orElse(SOME_DEFAULT);
}
Comment From: snicoll
It should also be noted that I don't think metadata for nested items will be generated in the arrangement above.
Comment From: mamachanko
That is a satisfactory explanation! I understand the reasoning.
This came up not so much because it is needed. But it was in a situation where I tried to convey the possibilities @ConfigurationProperties provides. I was genuinely convinced this would work.
Thanks @philwebb !
Comment From: colltoaction
@philwebb consider that Optional can be used in a functional way like:
String value = config.getMoreOptionalConfig().flatMap(MoreConfig::getSomeNestedProperty).orElse(SOME_DEFAULT);
Comment From: youngm
@philwebb I'd like to see Optional work with nested configuration properties someday. The second most voted answer to the stack overflow you linked to has some valid points: https://stackoverflow.com/a/26328314/1368209
You are perfectly welcome to have your opinion about Optionals. However, there is a large segment of the java development community that has a different opinion and would very much appreciate it if Spring Boot supported it. Thanks.