Skip to content

Resolve property placeholders in constructor binding default values - #51661

Merged
wilkinsona merged 2 commits into
spring-projects:mainfrom
Wanbinyu:gh-29495-default-value-placeholders
Sep 11, 2026
Merged

wilkinsona merged 2 commits into
spring-projects:mainfrom
Wanbinyu:gh-29495-default-value-placeholders

Conversation

@Wanbinyu

@Wanbinyu Wanbinyu commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Resolve property placeholders in @DefaultValue before converting constructor arguments, following the team decision in #29495 (comment).

For example, with defaults.duration=3d, a constructor parameter annotated with @DefaultValue("${defaults.duration:1d}") now receives Duration.ofDays(3) when no explicit value is configured for that parameter. Without defaults.duration, it receives Duration.ofDays(1).

The change uses the Binder's existing PlaceholdersResolver for each default value and String.valueOf to return the resolved values as a String[], consistently with PropertySourcesPlaceholdersResolver. Explicit property values still take precedence; empty @DefaultValue handling and ordinary field initializers are unchanged. Update the annotation's Javadoc accordingly.

Verification (Java 25):

  • Added real application-context tests using @EnableConfigurationProperties, checking the constructed bean's string, Duration, primitive-array and collection values. The initial reproduction failed before the production change (2 failing default-value cases, with the explicit-override control passing).
  • The application-context tests pass with the fix, including placeholder fallback values and explicit overrides.
  • Added Binder tests for no resolver, unresolved placeholders, and a custom resolver returning a non-string value.
  • Ran all core tests matching *context.properties.* and *boot.convert.*: 1,220 tests, 0 failures/errors, 1 skipped.
  • :core:spring-boot:checkstyleMain, checkstyleTest, checkFormatMain, and checkFormatTest passed.

This targets main, not a maintenance branch: resolving placeholders in defaults is an intentional behavior change for applications that previously received the literal placeholder. This does not change default-value collection conversion rules or resolve placeholders in ordinary field initializers. The entire repository test suite was not run.

Closes #29495.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue that has not yet been triaged. Contributions will not be accepted. label Sep 11, 2026
@Nullable Object[] resolved = new Object[defaultValue.length];
boolean strings = true;
for (int i = 0; i < defaultValue.length; i++) {
Object value = resolver.resolvePlaceholders(defaultValue[i]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For simplicity and consistency with PropertySourcesPlaceholdersResolver, I think String.valueOf(value) should be used here. That will remove the need for the strings boolean and allow a String[] to be returned.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Andy. Updated in bc60f1f to use String.valueOf(value), remove the strings flag and conditional array handling, and return String[]. The configuration-properties and conversion tests passed locally (1,220 tests, 0 failures/errors, 1 skipped), along with formatting and Checkstyle checks.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Sep 11, 2026
@wilkinsona wilkinsona self-assigned this Sep 11, 2026
Wanbinyu added a commit to Wanbinyu/spring-boot that referenced this pull request Sep 11, 2026
Use String.valueOf for consistency with PropertySourcesPlaceholdersResolver and remove the conditional array type handling.

See spring-projectsgh-51661

Signed-off-by: Wan bin yu <3431359639@qq.com>
@wilkinsona wilkinsona added type: enhancement A general enhancement and removed status: waiting-for-feedback We need additional information before we can continue status: waiting-for-triage An issue that has not yet been triaged. Contributions will not be accepted. labels Sep 11, 2026
@wilkinsona wilkinsona added this to the 4.2.x milestone Sep 11, 2026
Wanbinyu and others added 2 commits September 11, 2026 16:56
Resolve each annotated default using the binder placeholder resolver
before conversion.

Signed-off-by: Wan bin yu <3431359639@qq.com>

See spring-projectsgh-51661
…values"

See spring-projectsgh-51661

Signed-off-by: Andy Wilkinson <andy.wilkinson@broadcom.com>
@wilkinsona
wilkinsona force-pushed the gh-29495-default-value-placeholders branch from bc60f1f to b5dd521 Compare September 11, 2026 16:30
@wilkinsona wilkinsona modified the milestones: 4.2.x, 4.2.0-M2 Sep 11, 2026
@wilkinsona
wilkinsona merged commit 26b0e81 into spring-projects:main Sep 11, 2026
3 checks passed
@wilkinsona

Copy link
Copy Markdown
Member

Thank you, @Wanbinyu.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: enhancement A general enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Declared defaults do not get property references replace

3 participants