I'm pulling my hair out here. I want to use a Java record for my @ConfigurationProperties, providing default values to unspecified config properties. Here is a very simple example:
@ConfigurationProperties(prefix = "myconfig")
public record LoggingProperties (
String whatever,
String somethingToDefault
) {
public LoggingProperties(String whatever, String somethingToDefault) {
this.whatever = whatever;
this.somethingToDefault = somethingToDefault;
}
public LoggingProperties(String whatever) {
this(whatever, "whatever was specified, but not somethingToDefault");
}
public LoggingProperties() {
this("neither was specified", "neither was specified");
}
}
It seems, if I declare a noargs constructor, spring always calls that, regardless of what I actually have in my config file (application.yml)
The above will yield an instance, that when logged shows:
LoggingProperties[whatever=neither was specified, somethingToDefault=neither was specified]
, despite the fact that my config WAS specified.
If I delete the no-args constructor, I get an exception about No default constructor found;
If I add @ConstructorBinding to the allargs constructor I get:
LoggingProperties[whatever=value from file, somethingToDefault=null]
. i.e. it just called the annotated constructor, ignoring the one with 1 arg (despite that prop being declared in my yml).
I'm at a loss... Is this even possible?
EDIT: in my application.yml I have:
myconfig:
whatever: "value from file"
Praise the lord for documentation (it pays to read it)
Default values can be specified using @DefaultValue on a constructor parameter or, when using Java 16 or later, a record component. The conversion service will be applied to coerce the String value to the target type of a missing property.
So it seems I can skip the constructor mess, and just annotate the record fields with a @DefaultValue(value = "whatever default"), like so:
@ConfigurationProperties(prefix = "someprefix")
@ConstructorBinding
public record MyRecord (
@DefaultValue(value = "true")
boolean someProperty,
) {}