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
+    }
+}

Reply via email to