Restore lenient config handling#15949
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 7.0.x #15949 +/- ##
========================================
Coverage ? 49.36%
Complexity ? 16777
========================================
Files ? 1986
Lines ? 93336
Branches ? 16337
========================================
Hits ? 46071
Misses ? 40139
Partials ? 7126 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
This PR restores Spring Boot’s lenient/relaxed type conversion for values resolved via environment.getProperty(name, type) in Grails applications by ensuring the Spring Boot ApplicationConversionService is installed on the Environment during startup (fixing actuator management.endpoint.*.access enum conversion such as unrestricted / read-only).
Changes:
- Delegate
GrailsApp.configureEnvironment(...)toSpringApplication’s implementation to install theApplicationConversionService. - Add a new core unit test verifying relaxed enum conversion via
environment.getProperty(..., Enum)in a minimalGrailsAppboot. - Update the external-configuration functional example to include the problematic actuator config and add an integration spec asserting relaxed enum conversion against the running app’s
Environment.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
grails-core/src/main/groovy/grails/boot/GrailsApp.groovy |
Delegates configureEnvironment to Spring Boot to restore application-level conversion service installation. |
grails-core/src/test/groovy/grails/boot/GrailsAppEnvironmentConversionSpec.groovy |
Regression test for relaxed enum conversion through environment.getProperty. |
grails-test-examples/external-configuration/grails-app/conf/application.yml |
Adds actuator endpoint access values that previously broke startup to reproduce the issue in the example app. |
grails-test-examples/external-configuration/src/integration-test/groovy/test/app/RelaxedPropertyResolutionSpec.groovy |
Integration regression tests validating conversion service behavior in the example app environment. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
The suggestion to scope the grails-test-examples/external-configuration/grails-app/conf/application.yml |
codeconsole
left a comment
There was a problem hiding this comment.
LGTM. Verified the core claim against the Spring Boot 3.5.16 bytecode the build resolves: SpringApplication.configureEnvironment() does exactly three things — installs a new ApplicationConversionService (guarded by addConversionService, default true), calls configurePropertySources() (the same call the old code made directly, so no double invocation and no ordering change for the profile logic that follows), and calls configureProfiles(), which has an empty body in Boot 3.5. Delegating to super is a clean restoration of the Boot contract.
Also confirmed no other entry point needs the same fix: GrailsSwingConsole, GrailsShell, and DevelopmentGrailsApplication all extend GrailsApp without overriding configureEnvironment, so they inherit it, and no other override exists in the repo.
Tests are well-placed: the unit spec follows the existing GrailsAppPidFileSpec pattern and fails without the fix, and since the pre-fix failure mode was startup failure, booting the external-configuration app with the issue's exact yml is itself the regression test. Nice that setAddConversionService(false) remains as an escape hatch if the new leniency ever causes trouble for an app.
A couple of non-blocking observations inline.
Description
Fixes #15818
Grails applications reject lenient configuration values (e.g. lowercase enum names) that work in plain Spring Boot applications. For example, this standard actuator configuration causes the application to fail on startup:
Invalid value 'unrestricted' for configuration property 'management.endpoint.heapdump.access' ...
Failed to convert to type org.springframework.boot.actuate.endpoint.Access
Root cause: GrailsApp has overridden SpringApplication.configureEnvironment() since Grails 3 without delegating to super. Spring Boot's implementation installs the ApplicationConversionService on the environment, which provides the lenient converters (lowercase/hyphenated enum names, durations, etc.). Because Grails skipped that step, the environment fell back to a plain DefaultConversionService, whose string-to-enum conversion is case-sensitive. This only affects properties resolved directly through environment.getProperty(name, type) — such as the actuator's PropertiesEndpointAccessResolver — since @ConfigurationProperties binding supplies its own conversion service.affects properties resolved directly through environment.getProperty(name, type) — such as the actuator's PropertiesEndpointAccessResolver — since @ConfigurationProperties binding supplies its own conversion service.
Change: GrailsApp.configureEnvironment() now delegates to super.configureEnvironment(environment, args) in place of the direct configurePropertySources() call. This installs the conversion service while preserving identical behavior otherwise (configureProfiles() is an empty method in Spring Boot 3.x, and the Grails-specific profile handling is unchanged).
Tests:
Contributor Checklist
Issue and Scope
Code Quality
Licensing and Attribution
Documentation