You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@grails.apache.org by "jdaugherty (via GitHub)" <gi...@apache.org> on 2026/07/09 20:32:24 UTC
[PR] Restore lenient config handling for Spring configuration [grails-core]
jdaugherty opened a new pull request, #15949:
URL: https://github.com/apache/grails-core/pull/15949
## 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:
```yml
management:
endpoint:
heapdump:
access: unrestricted
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:
- GrailsAppEnvironmentConversionSpec (grails-core) boots a minimal GrailsApp and verifies lowercase (unrestricted) and hyphenated (read-only) enum values resolve via environment.getProperty(). This spec fails without the fix.
- The grails-test-examples/external-configuration functional app now declares the exact configuration from the issue (management.endpoint.heapdump.access: unrestricted, threaddump.access: read-only), which previously prevented startup, and the new RelaxedPropertyResolutionSpec verifies both values resolve to the Access enum through the Spring environment.
Contributor Checklist
Issue and Scope
- [x] This PR is linked to an existing issue that has been acknowledged or approved by the project team.
- [x] This PR addresses the complete scope of the linked issue.
- [x] This PR contains a single, focused change.
- [x] This PR targets the correct branch for the type of change (bug fix targeting 7.0.x).
Code Quality
- [x] I have added or updated tests that cover the changes introduced in this PR.
- [ ] I have verified that all existing tests pass by running ./gradlew build --rerun-tasks.
- [x] My code follows the project's code style guidelines.
- [x] This PR does not include mass reformatting, style-only changes, or large-scale refactoring.
- [x] If generative AI tooling was used in preparing this contribution, a quality model was used to ensure contributions are consistent with the project's quality standards.
Licensing and Attribution
- [x] All contributed code is provided under the Apache License 2.0, and new source files include the appropriate Apache license header.
- [x] I have the necessary rights to submit this contribution and confirm it is my own original work.
- [x] If generative AI tooling was used in preparing this contribution, I have followed the ASF's policy on generative tooling and have properly attributed its use.
Documentation
- [x] If this PR introduces user-facing changes, I have included or updated the relevant documentation. (No doc change needed — this restores documented Spring Boot behavior; no new or changed public API.)
- [x] If this PR adds a new feature, I have updated the What's New section. (N/A — bug fix.)
- [x] If this PR introduces breaking changes... (N/A — no user action required.)
- [x] The PR description clearly explains what was changed and why.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Restore lenient config handling for Spring configuration [grails-core]
Posted by "codeconsole (via GitHub)" <gi...@apache.org>.
codeconsole commented on code in PR #15949:
URL: https://github.com/apache/grails-core/pull/15949#discussion_r3557222309
##########
grails-test-examples/external-configuration/src/integration-test/groovy/test/app/RelaxedPropertyResolutionSpec.groovy:
##########
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package test.app
+
+import grails.testing.mixin.integration.Integration
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.actuate.endpoint.Access
+import org.springframework.boot.convert.ApplicationConversionService
+import org.springframework.core.env.ConfigurableEnvironment
+import spock.lang.Specification
+
+/**
+ * Regression tests for issue #15818. Actuator endpoint access is resolved directly through
+ * {@code environment.getProperty(name, Access)} rather than relaxed configuration-property
+ * binding, so the environment itself must be configured with the
+ * {@link ApplicationConversionService} for lenient values such as {@code unrestricted} or
+ * {@code read-only} to convert. Before the fix the application failed to start with the
+ * {@code management.endpoint.*.access} values declared in {@code application.yml}.
+ */
+@Integration
+class RelaxedPropertyResolutionSpec extends Specification {
+
+ @Autowired
+ ConfigurableEnvironment springEnvironment
+
+ void 'the environment uses the ApplicationConversionService'() {
+ expect: 'the conversion service installed by Spring Boot is present'
+ springEnvironment.conversionService instanceof ApplicationConversionService
Review Comment:
Observation: the two enum-resolution features below already prove everything this feature asserts, so this one is technically redundant — but it's useful as a first-failure diagnostic that distinguishes "conversion service missing" from "converter behavior changed", and it documents intent. No change needed.
##########
grails-core/src/main/groovy/grails/boot/GrailsApp.groovy:
##########
@@ -133,7 +133,9 @@ class GrailsApp extends SpringApplication {
@Override
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
- configurePropertySources(environment, args)
+ // Delegating to super installs the ApplicationConversionService so relaxed property
+ // resolution (e.g. lowercase enum values) works via environment.getProperty()
+ super.configureEnvironment(environment, args)
Review Comment:
Two side effects of this delegation worth noting (neither blocking):
1. `GrailsApplicationPostProcessor.loadApplicationConfig()` mutates `environment.getConversionService()` via `addConverter(...)` and then propagates it into `PropertySourcesConfig`. That still works only because Boot 3.5 installs a **new mutable** `ApplicationConversionService` here rather than the unmodifiable `ApplicationConversionService.getSharedInstance()`. If a future Boot version switches to the shared instance, those `addConverter` calls will throw at startup — worth remembering during Boot upgrades.
2. Because that same conversion service flows into `PropertySourcesConfig`, typed access through `grailsApplication.config.getProperty(name, type)` also becomes lenient (durations, lowercase/hyphenated enums, delimited collections, formatters), not just `environment.getProperty()`. It's strictly in the direction of Spring Boot alignment, so I consider it a plus — but the behavior change is a bit broader than the PR description states. Maybe add a sentence to the description so it's discoverable later.
##########
grails-core/src/test/groovy/grails/boot/GrailsAppEnvironmentConversionSpec.groovy:
##########
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package grails.boot
+
+import grails.util.Environment
+import org.springframework.boot.WebApplicationType
+import org.springframework.boot.convert.ApplicationConversionService
+import org.springframework.context.ConfigurableApplicationContext
+import org.springframework.context.annotation.Configuration
+import spock.lang.Specification
+import spock.util.environment.RestoreSystemProperties
+
+/**
+ * Verifies the application environment created by {@link GrailsApp} supports the same
+ * relaxed property resolution as a plain Spring Boot application, so values resolved
+ * directly through {@code environment.getProperty(name, Enum)} accept lenient formats
+ * such as lowercase or hyphenated enum names (see issue #15818).
+ */
+@RestoreSystemProperties
+class GrailsAppEnvironmentConversionSpec extends Specification {
+
+ void "environment resolves relaxed enum property values"() {
+ setup:
+ System.setProperty(Environment.KEY, Environment.TEST.getName())
+ System.setProperty('test.access.lowercase', 'unrestricted')
+ System.setProperty('test.access.hyphenated', 'read-only')
+ GrailsApp app = new GrailsApp(EnvironmentConversionTestConfiguration)
+ app.webApplicationType = WebApplicationType.NONE
+
+ when:
+ ConfigurableApplicationContext context = app.run()
+
+ then:
+ context.environment.conversionService instanceof ApplicationConversionService
Review Comment:
Nit: this asserts a Boot implementation detail on top of the behavioral assertions below it, but since the installed conversion service *is* the contract being restored (and it would still pass if Boot ever reverted to `getSharedInstance()`, which is also an `ApplicationConversionService`), it works well as a diagnostic — when this line fails you know the service was never installed, vs. a converter behavior change. Fine as is.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Restore lenient config handling for Spring configuration [grails-core]
Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15949:
URL: https://github.com/apache/grails-core/pull/15949#discussion_r3555264509
##########
grails-test-examples/external-configuration/grails-app/conf/application.yml:
##########
@@ -99,6 +99,15 @@ environments:
jdbcInterceptors: ConnectionState
defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED
---
+# Lenient enum values resolved via environment.getProperty(name, Access) rather than
+# relaxed configuration-property binding - regression test for issue #15818
+management:
+ endpoint:
+ heapdump:
+ access: unrestricted
+ threaddump:
+ access: read-only
Review Comment:
Let's leave this. They're only designed to run locally.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Restore lenient config handling for Spring configuration [grails-core]
Posted by "testlens-app[bot] (via GitHub)" <gi...@apache.org>.
testlens-app[bot] commented on PR #15949:
URL: https://github.com/apache/grails-core/pull/15949#issuecomment-4930076415
## ✅ All tests passed ✅
🏷️ Commit: 40be754c681a25a58bfd61ce3da79eb7c7edb6a7
▶️ Tests: 6954 executed
⚪️ Checks: 61/61 completed
---
_Learn more about TestLens at [testlens.app](https://testlens.app)._
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Restore lenient config handling for Spring configuration [grails-core]
Posted by "codecov[bot] (via GitHub)" <gi...@apache.org>.
codecov[bot] commented on PR #15949:
URL: https://github.com/apache/grails-core/pull/15949#issuecomment-4929584896
## [Codecov](https://app.codecov.io/gh/apache/grails-core/pull/15949?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) Report
:white_check_mark: All modified and coverable lines are covered by tests.
:warning: Please [upload](https://docs.codecov.com/docs/codecov-uploader) report for BASE (`7.0.x@34bc9e9`). [Learn more](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#section-missing-base-commit) about missing BASE report.
<details><summary>Additional details and impacted files</summary>
```diff
@@ Coverage Diff @@
## 7.0.x #15949 +/- ##
========================================
Coverage ? 49.36%
Complexity ? 16777
========================================
Files ? 1986
Lines ? 93336
Branches ? 16337
========================================
Hits ? 46071
Misses ? 40139
Partials ? 7126
```
</details>
[:umbrella: View full report in Codecov by Harness](https://app.codecov.io/gh/apache/grails-core/pull/15949?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
<details><summary> :rocket: New features to boost your workflow: </summary>
- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Restore lenient config handling for Spring configuration [grails-core]
Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #15949:
URL: https://github.com/apache/grails-core/pull/15949#discussion_r3555251634
##########
grails-test-examples/external-configuration/grails-app/conf/application.yml:
##########
@@ -99,6 +99,15 @@ environments:
jdbcInterceptors: ConnectionState
defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED
---
+# Lenient enum values resolved via environment.getProperty(name, Access) rather than
+# relaxed configuration-property binding - regression test for issue #15818
+management:
+ endpoint:
+ heapdump:
+ access: unrestricted
+ threaddump:
+ access: read-only
Review Comment:
This example app’s default config sets `management.endpoint.heapdump.access: unrestricted` for all profiles. Even though it’s for a regression test, it’s easy to run this sample outside tests, and an unrestricted heapdump endpoint is a risky default. Consider scoping this YAML document to the `test` profile (or the integration-test profile you run these specs under) so the relaxed-value fixture doesn’t weaken non-test runs of the example app.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Restore lenient config handling [grails-core]
Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty merged PR #15949:
URL: https://github.com/apache/grails-core/pull/15949
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Restore lenient config handling [grails-core]
Posted by "jdaugherty (via GitHub)" <gi...@apache.org>.
jdaugherty commented on code in PR #15949:
URL: https://github.com/apache/grails-core/pull/15949#discussion_r3558698537
##########
grails-core/src/main/groovy/grails/boot/GrailsApp.groovy:
##########
@@ -133,7 +133,9 @@ class GrailsApp extends SpringApplication {
@Override
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
- configurePropertySources(environment, args)
+ // Delegating to super installs the ApplicationConversionService so relaxed property
+ // resolution (e.g. lowercase enum values) works via environment.getProperty()
+ super.configureEnvironment(environment, args)
Review Comment:
I've updated the comment & PR description
##########
grails-core/src/main/groovy/grails/boot/GrailsApp.groovy:
##########
@@ -133,7 +133,9 @@ class GrailsApp extends SpringApplication {
@Override
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
- configurePropertySources(environment, args)
+ // Delegating to super installs the ApplicationConversionService so relaxed property
+ // resolution (e.g. lowercase enum values) works via environment.getProperty()
+ super.configureEnvironment(environment, args)
Review Comment:
I've updated the comment & PR title
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] Restore lenient config handling for Spring configuration [grails-core]
Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #15949:
URL: https://github.com/apache/grails-core/pull/15949#issuecomment-4930189333
<!-- Bito Reply -->
The suggestion to scope the `management.endpoint.heapdump.access: unrestricted` configuration to a specific profile is appropriate. Currently, this configuration is applied globally in `grails-test-examples/external-configuration/grails-app/conf/application.yml`, which could inadvertently expose the heapdump endpoint in non-test environments. Scoping it to the `test` profile would ensure this relaxed security setting is only active during testing.
**grails-test-examples/external-configuration/grails-app/conf/application.yml**
```
---
# Lenient enum values resolved via environment.getProperty(name, Access) rather than
# relaxed configuration-property binding - regression test for issue #15818
spring:
profiles: test
management:
endpoint:
heapdump:
access: unrestricted
threaddump:
access: read-only
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: notifications-unsubscribe@grails.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org