This is an automated email from the ASF dual-hosted git repository. jdaugherty pushed a commit to branch worktree-fix-15818-conversion-service in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 40be754c681a25a58bfd61ce3da79eb7c7edb6a7 Author: James Daugherty <[email protected]> AuthorDate: Thu Jul 9 16:29:17 2026 -0400 Restore lenient config handling for Spring configuration --- .../src/main/groovy/grails/boot/GrailsApp.groovy | 4 +- .../boot/GrailsAppEnvironmentConversionSpec.groovy | 67 ++++++++++++++++++++++ .../grails-app/conf/application.yml | 9 +++ .../test/app/RelaxedPropertyResolutionSpec.groovy | 56 ++++++++++++++++++ 4 files changed, 135 insertions(+), 1 deletion(-) diff --git a/grails-core/src/main/groovy/grails/boot/GrailsApp.groovy b/grails-core/src/main/groovy/grails/boot/GrailsApp.groovy index 16bc28b2a8..70f79a0b4c 100644 --- a/grails-core/src/main/groovy/grails/boot/GrailsApp.groovy +++ b/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) String[] springProfile = environment.getProperty(SPRING_PROFILES, String[]) if (springProfile) { diff --git a/grails-core/src/test/groovy/grails/boot/GrailsAppEnvironmentConversionSpec.groovy b/grails-core/src/test/groovy/grails/boot/GrailsAppEnvironmentConversionSpec.groovy new file mode 100644 index 0000000000..c8e1bdc49b --- /dev/null +++ b/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 + context.environment.getProperty('test.access.lowercase', TestEndpointAccess) == TestEndpointAccess.UNRESTRICTED + context.environment.getProperty('test.access.hyphenated', TestEndpointAccess) == TestEndpointAccess.READ_ONLY + + cleanup: + context?.close() + } + + static enum TestEndpointAccess { + NONE, + READ_ONLY, + UNRESTRICTED + } +} + +@Configuration +class EnvironmentConversionTestConfiguration { +} diff --git a/grails-test-examples/external-configuration/grails-app/conf/application.yml b/grails-test-examples/external-configuration/grails-app/conf/application.yml index 9f39f11d0c..2a22f26c5c 100644 --- a/grails-test-examples/external-configuration/grails-app/conf/application.yml +++ b/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 +--- test: config: number: 12345 diff --git a/grails-test-examples/external-configuration/src/integration-test/groovy/test/app/RelaxedPropertyResolutionSpec.groovy b/grails-test-examples/external-configuration/src/integration-test/groovy/test/app/RelaxedPropertyResolutionSpec.groovy new file mode 100644 index 0000000000..5ef886b68d --- /dev/null +++ b/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 + } + + void 'a lowercase enum value resolves through environment.getProperty'() { + expect: 'the lenient value from application.yml converts to the Access enum' + springEnvironment.getProperty('management.endpoint.heapdump.access', Access) == Access.UNRESTRICTED + } + + void 'a hyphenated enum value resolves through environment.getProperty'() { + expect: 'the lenient value from application.yml converts to the Access enum' + springEnvironment.getProperty('management.endpoint.threaddump.access', Access) == Access.READ_ONLY + } +}
