From 93643b4a3348dcc97683da39391370b3a4a83d08 Mon Sep 17 00:00:00 2001 From: James Daugherty Date: Mon, 4 May 2026 21:14:36 -0400 Subject: [PATCH] #10279 - add test to show issue no longer exists --- grails-test-examples/issue-10279/build.gradle | 48 ++++++++++++++++ .../grails-app/conf/application.groovy | 26 +++++++++ .../grails-app/conf/application.yml | 44 +++++++++++++++ .../issue-10279/grails-app/conf/logback.xml | 39 +++++++++++++ .../controllers/issue10279/UrlMappings.groovy | 25 +++++++++ .../init/issue10279/Application.groovy | 28 ++++++++++ .../issue10279/ActuatorEnvClosureSpec.groovy | 56 +++++++++++++++++++ settings.gradle | 2 + 8 files changed, 268 insertions(+) create mode 100644 grails-test-examples/issue-10279/build.gradle create mode 100644 grails-test-examples/issue-10279/grails-app/conf/application.groovy create mode 100644 grails-test-examples/issue-10279/grails-app/conf/application.yml create mode 100644 grails-test-examples/issue-10279/grails-app/conf/logback.xml create mode 100644 grails-test-examples/issue-10279/grails-app/controllers/issue10279/UrlMappings.groovy create mode 100644 grails-test-examples/issue-10279/grails-app/init/issue10279/Application.groovy create mode 100644 grails-test-examples/issue-10279/src/integration-test/groovy/issue10279/ActuatorEnvClosureSpec.groovy diff --git a/grails-test-examples/issue-10279/build.gradle b/grails-test-examples/issue-10279/build.gradle new file mode 100644 index 00000000000..84191ade8f0 --- /dev/null +++ b/grails-test-examples/issue-10279/build.gradle @@ -0,0 +1,48 @@ +/* + * 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. + */ +plugins { + id 'org.apache.grails.buildsrc.properties' + id 'org.apache.grails.buildsrc.dependency-validator' + id 'org.apache.grails.buildsrc.compile' +} + +version = '0.1' +group = 'issue10279' + +apply plugin: 'org.apache.grails.gradle.grails-web' + +dependencies { + implementation platform(project(':grails-bom')) + + implementation 'org.springframework.boot:spring-boot-starter-logging' + implementation 'org.apache.grails:grails-dependencies-starter-web' + + testAndDevelopmentOnly platform(project(':grails-bom')) + + testImplementation 'org.apache.grails:grails-testing-support-web' + testImplementation 'org.spockframework:spock-core' + + integrationTestImplementation 'com.fasterxml.jackson.core:jackson-databind' + integrationTestImplementation project(':grails-testing-support-http-client') +} + +apply { + from rootProject.layout.projectDirectory.file('gradle/functional-test-config.gradle') + from rootProject.layout.projectDirectory.file('gradle/grails-extension-gradle-config.gradle') +} diff --git a/grails-test-examples/issue-10279/grails-app/conf/application.groovy b/grails-test-examples/issue-10279/grails-app/conf/application.groovy new file mode 100644 index 00000000000..78799b9716a --- /dev/null +++ b/grails-test-examples/issue-10279/grails-app/conf/application.groovy @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// Reproduces issue #10279: defining a closure in application.groovy causes +// Jackson serialization failures when the Spring Boot Actuator /actuator/env +// endpoint is accessed. +grails.gorm.default.mapping = { + cache true + version false +} + +grails.normal.string.property = 'hello-from-groovy-config' diff --git a/grails-test-examples/issue-10279/grails-app/conf/application.yml b/grails-test-examples/issue-10279/grails-app/conf/application.yml new file mode 100644 index 00000000000..84ab47ee2ed --- /dev/null +++ b/grails-test-examples/issue-10279/grails-app/conf/application.yml @@ -0,0 +1,44 @@ +# 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. + +info: + app: + name: '@info.app.name@' + version: '@info.app.version@' + grailsVersion: '@info.app.grailsVersion@' + +grails: + profile: web + codegen: + defaultPackage: issue10279 + mime: + types: + all: '*/*' + json: + - application/json + - text/json + xml: + - text/xml + - application/xml + +# Expose the /actuator/env endpoint so the functional test can hit it. +management: + endpoints: + web: + exposure: + include: 'env,health' + endpoint: + env: + show-values: always diff --git a/grails-test-examples/issue-10279/grails-app/conf/logback.xml b/grails-test-examples/issue-10279/grails-app/conf/logback.xml new file mode 100644 index 00000000000..d64fd5d7122 --- /dev/null +++ b/grails-test-examples/issue-10279/grails-app/conf/logback.xml @@ -0,0 +1,39 @@ + + + + + + + + + true + + UTF-8 + %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n%wex + + + + + + + + diff --git a/grails-test-examples/issue-10279/grails-app/controllers/issue10279/UrlMappings.groovy b/grails-test-examples/issue-10279/grails-app/controllers/issue10279/UrlMappings.groovy new file mode 100644 index 00000000000..8e1507a8042 --- /dev/null +++ b/grails-test-examples/issue-10279/grails-app/controllers/issue10279/UrlMappings.groovy @@ -0,0 +1,25 @@ +/* + * 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 issue10279 + +class UrlMappings { + static mappings = { + "/$controller/$action?/$id?(.$format)?" { + constraints {} + } + } +} diff --git a/grails-test-examples/issue-10279/grails-app/init/issue10279/Application.groovy b/grails-test-examples/issue-10279/grails-app/init/issue10279/Application.groovy new file mode 100644 index 00000000000..3c03e24a3ab --- /dev/null +++ b/grails-test-examples/issue-10279/grails-app/init/issue10279/Application.groovy @@ -0,0 +1,28 @@ +/* + * 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 issue10279 + +import grails.boot.GrailsApp +import grails.boot.config.GrailsAutoConfiguration +import groovy.transform.CompileStatic + +@CompileStatic +class Application extends GrailsAutoConfiguration { + static void main(String[] args) { + GrailsApp.run(Application, args) + } +} diff --git a/grails-test-examples/issue-10279/src/integration-test/groovy/issue10279/ActuatorEnvClosureSpec.groovy b/grails-test-examples/issue-10279/src/integration-test/groovy/issue10279/ActuatorEnvClosureSpec.groovy new file mode 100644 index 00000000000..7ad8fa2dfd4 --- /dev/null +++ b/grails-test-examples/issue-10279/src/integration-test/groovy/issue10279/ActuatorEnvClosureSpec.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 issue10279 + +import spock.lang.Specification +import spock.lang.Tag + +import grails.testing.mixin.integration.Integration +import org.apache.grails.testing.http.client.HttpClientSupport + +/** + * Regression test for GitHub issue #10279. + * + * When application.groovy defines closure-valued properties (e.g. grails.gorm.default.mapping), + * the Spring Boot Actuator /actuator/env endpoint must not throw a Jackson serialization error. + * + * In Grails 3.x this caused a JsonMappingException because the Closure held a delegate chain + * that referenced GroovyClassLoader internals, which Jackson could not serialize. + */ +@Integration +@Tag('http-client') +class ActuatorEnvClosureSpec extends Specification implements HttpClientSupport { + + void 'actuator /env endpoint returns 200 when application.groovy contains closure-valued config'() { + when: 'the actuator environment endpoint is accessed' + def response = http('/actuator/env') + + then: 'it responds successfully without a Jackson serialization error (issue #10279)' + response.assertStatus(200) + } + + void 'actuator /env endpoint response contains normal string properties from application.groovy'() { + when: 'the actuator environment endpoint is accessed' + def response = http('/actuator/env') + + then: 'it responds successfully' + response.assertStatus(200) + + and: 'the string property defined in application.groovy is present in the response' + response.assertContains('hello-from-groovy-config') + } +} diff --git a/settings.gradle b/settings.gradle index df1adbe0a0c..1299004b372 100644 --- a/settings.gradle +++ b/settings.gradle @@ -401,6 +401,7 @@ include( 'grails-test-examples-plugins-issue11005', 'grails-test-examples-issue-11767', 'grails-test-examples-issue-15228', + 'grails-test-examples-issue-10279', 'grails-test-examples-plugins-exploded', 'grails-test-examples-plugins-issue-11767', 'grails-test-examples-plugins-micronaut-singleton', @@ -439,6 +440,7 @@ project(':grails-test-examples-plugins-loadafter').projectDir = file('grails-tes project(':grails-test-examples-plugins-issue11005').projectDir = file('grails-test-examples/plugins/issue11005') project(':grails-test-examples-issue-11767').projectDir = file('grails-test-examples/issue-11767') project(':grails-test-examples-issue-15228').projectDir = file('grails-test-examples/issue-15228') +project(':grails-test-examples-issue-10279').projectDir = file('grails-test-examples/issue-10279') project(':grails-test-examples-plugins-exploded').projectDir = file('grails-test-examples/plugins/exploded') project(':grails-test-examples-plugins-issue-11767').projectDir = file('grails-test-examples/plugins/issue-11767') project(':grails-test-examples-plugins-micronaut-singleton').projectDir = file('grails-test-examples/plugins/micronaut-singleton')