Automate configuration metadata for @ConfigurationProperties modules - #16047
Automate configuration metadata for @ConfigurationProperties modules#16047jamesfredley wants to merge 18 commits into
Conversation
Assisted-by: opencode:gpt-5.6-sol
Assisted-by: opencode:gpt-5.6-sol
Assisted-by: opencode:gpt-5.6-sol
Assisted-by: opencode:gpt-5.6-sol
Assisted-by: opencode:gpt-5.6-sol
Assisted-by: opencode:gpt-5.6-sol
Assisted-by: opencode:gpt-5.6-sol
Assisted-by: opencode:gpt-5.6-sol
Assisted-by: opencode:gpt-5.6-sol
Assisted-by: opencode:gpt-5.6-sol
There was a problem hiding this comment.
Pull request overview
Introduces a new build-time pipeline to generate Spring Boot configuration metadata from compiled Groovy/Java @ConfigurationProperties classes, merging in curated additional-spring-configuration-metadata.json overlays and wiring the results into the docs config reference generation.
Changes:
- Adds
grails-configuration-metadatacompiler module with a Groovy SEMANTIC_ANALYSIS AST transformation to embed deterministic metadata payloads in compiled Groovy configuration classes. - Adds a Gradle build-logic plugin (
org.apache.grails.buildsrc.configuration-metadata) that scans compiled bytecode (ASM), merges curated overlays, and publishes a single standardMETA-INF/spring-configuration-metadata.jsonresource per jar. - Migrates existing curated metadata to
additional-spring-configuration-metadata.json, relocates CORS metadata ownership to URL Mappings, and expands the docs config-reference pipeline inputs.
Reviewed changes
Copilot reviewed 19 out of 22 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| settings.gradle | Includes new grails-configuration-metadata module in the multi-project build. |
| gradle/publish-root-config.gradle | Publishes the new grails-configuration-metadata module. |
| dependencies.gradle | Adds ASM to the build BOM dependencies for bytecode scanning. |
| build-logic/plugins/build.gradle | Adds ASM dependency and registers the new configuration metadata Gradle plugin. |
| build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/ConfigurationMetadataPlugin.groovy | Implements bytecode scanning + overlay merge + deterministic metadata output task wired into processResources. |
| build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/ConfigurationMetadataPluginSpec.groovy | TestKit coverage for clean/incremental/edit/deletion/overlay/duplicates/no-overlay behavior. |
| grails-configuration-metadata/build.gradle | New compiler module build definition and test dependencies. |
| grails-configuration-metadata/src/main/groovy/org/apache/grails/configuration/metadata/ConfigurationMetadataTransformation.groovy | Groovy AST transform embedding per-class metadata payloads (constant defaults only). |
| grails-configuration-metadata/src/main/resources/META-INF/services/org.codehaus.groovy.transform.ASTTransformation | Registers the global AST transformation. |
| grails-configuration-metadata/src/test/groovy/org/apache/grails/configuration/metadata/ConfigurationMetadataTransformationSpec.groovy | Unit tests validating payload shape, defaults policy, and reserved-field collision handling. |
| grails-cache/build.gradle | Applies the new configuration metadata build plugin. |
| grails-cache/src/main/resources/META-INF/additional-spring-configuration-metadata.json | Adds curated cache metadata overlay for merge with generated metadata. |
| grails-databinding/build.gradle | Applies the new configuration metadata build plugin. |
| grails-databinding/src/main/resources/META-INF/additional-spring-configuration-metadata.json | Adds curated data binding metadata overlay. |
| grails-views-gson/build.gradle | Applies the new configuration metadata build plugin. |
| grails-views-gson/src/main/resources/META-INF/additional-spring-configuration-metadata.json | Adds curated JSON Views metadata overlay. |
| grails-views-markup/build.gradle | Applies the new configuration metadata build plugin. |
| grails-web-url-mappings/build.gradle | Applies the new configuration metadata build plugin. |
| grails-web-url-mappings/src/main/resources/META-INF/additional-spring-configuration-metadata.json | Adds curated URL Mappings/CORS metadata overlay (migrated from web-core). |
| grails-web-core/src/main/resources/META-INF/spring-configuration-metadata.json | Removes CORS group/properties now owned by URL Mappings. |
| grails-doc/src/en/guide/conf/config.adoc | Documents how Grails produces/overlays configuration metadata and its defaults policy. |
| grails-doc/build.gradle | Adds migrated module jars as inputs to the configuration reference generation pipeline. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## 8.0.x #16047 +/- ##
==================================================
+ Coverage 54.7156% 54.7471% +0.0315%
- Complexity 20402 20483 +81
==================================================
Files 2098 2099 +1
Lines 100931 101114 +183
Branches 17900 17951 +51
==================================================
+ Hits 55225 55357 +132
- Misses 37842 37864 +22
- Partials 7864 7893 +29
🚀 New features to boost your workflow:
|
|
We had discussed creating a custom solution and not requiring ConfigurationProperties in the meeting, why the reversal here now? |
jdaugherty
left a comment
There was a problem hiding this comment.
I had AI review this and then iterated with the review. I think the @Delegate finding is rather important. Review follows.
Read through the compiler module, the Gradle plugin and the five module migrations, then ran generateConfigurationMetadata for all five modules plus :grails-doc:generateConfigReference on this branch to diff the actual output. The mechanism works: the ASM path and the Groovy payload path both produce correct metadata for Java and Groovy config classes, and cache / data binding / JSON views / CORS come through with no loss. The TestKit spec covers clean, incremental, edit, delete and overlay behaviour well.
One thing I would want resolved before this goes in: the Application Properties reference regresses. 33 of 187 rows come out with an empty description and an empty default (24 grails.views.markup.*, 9 newly inferred grails.views.json.*). Every other row in that file has a description, so this PR introduces all 33.
The remaining comments are about how quietly the generated half can drift from what Boot actually binds (the @Delegate blind spot and the isNested heuristic), how thinly the transform itself is covered, and a question about publishing the compiler module.
This review is on the implementation as written; it does not address the separate open question about whether the approach should require @ConfigurationProperties.
| project(':grails-data-mongodb').tasks.named('jar'), | ||
| project(':grails-views-gson').tasks.named('jar') | ||
| project(':grails-views-gson').tasks.named('jar'), | ||
| project(':grails-views-markup').tasks.named('jar'), |
There was a problem hiding this comment.
Wiring these two jars into generateConfigReference publishes the generated metadata straight into the Application Properties reference, and grails-views-markup has no curated overlay. Generating the reference from this branch:
- 33 of 187 rows now have an empty Description and an empty Default: all 24
grails.views.markup.*, plus the 9 newly inferredgrails.views.json.*entries (baseTemplateClass,cache,enableReloading,extension,packageImports,packageName,staticImports,templatePath,useAbsoluteLinks). Every pre-existing row in that file has a description, so all 33 blanks are new. - The markup rows land inside the existing "Views & GSP" section, interleaved with fully documented
grails.views.gsp.*rows, so they read as holes in an otherwise complete table.
Every one of these is settable, so every one needs documenting. Can we add grails-views-markup/src/main/resources/META-INF/additional-spring-configuration-metadata.json with a group description plus a description and default for each of the 24, and descriptions for the 9 new JSON Views entries, before these jars feed the reference?
Cover inherited and excluded setters, constructor selection, deferred prefixes, complex type names, JSON escaping, interfaces, and unprefixed configuration properties. Assisted-by: opencode:gpt-5.6-sol
Preserve both build-logic plugin registrations and consolidate their shared ASM dependency while integrating the current base branch. Assisted-by: opencode:gpt-5.6-sol
Add curated descriptions and authoritative defaults for the Markup and JSON Views properties included in the generated application reference. Assisted-by: opencode:gpt-5.6-sol
Make duplicate class rejection explicit and retain legal repeated groups by their source provenance with deterministic overlay merging. Assisted-by: opencode:gpt-5.6-sol
Remove publication and BOM wiring for the build-only AST transform module, and drop its unused production Spring Boot dependency. Assisted-by: opencode:gpt-5.6-sol
Warn when delegated properties require explicit metadata and limit nested expansion to inner or annotated JavaBean properties. Assisted-by: opencode:gpt-5.6-sol
Keep unannotated top-level constructor properties scalar while preserving inner and explicitly annotated nested configuration properties. Assisted-by: opencode:gpt-5.6-sol
GitHub's cached mergeable state was stale, computed against an older 8.0.x commit than current tip. This branch merges cleanly against the current 8.0.x tip with no textual conflicts; verified by running the full test suites for grails-configuration-metadata, build-logic, and the five migrated modules (cache, databinding, gson, markup views, url-mappings) with no new failures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
🚨 TestLens detected 1 failed test 🚨Here is what you can do:
Test SummaryCI / Functional Tests (Java 21, indy=true) > :grails-test-examples-scaffolding:integrationTest
🏷️ Commit: b770e0b Test FailuresUserControllerSpec > User list (:grails-test-examples-scaffolding:integrationTest in CI / Functional Tests (Java 21, indy=true))Rerun ControlsSelect tests to mute in this pull request:
Reuse successful test results:
Click the checkbox to trigger a rerun:
Learn more about TestLens at testlens.app/docs. |
What this does
Closes #15469 for the five modules that already use
@ConfigurationProperties:grails-cachegrails-databindinggrails-views-gsongrails-views-markupgrails-web-url-mappings(CORS owner)Each publishes standard Spring Boot metadata at
META-INF/spring-configuration-metadata.jsonduring the module build. IDEs,config-report, and the Application Properties reference consume that resource.This is not Spring Boot's
spring-boot-configuration-processor. That approach was tried in #15566 and closed because Java annotation processors break incremental Groovy compilation. This PR uses a Grails-owned path instead:@ConfigurationPropertiesclass (no shared processor output).Migration details
spring-configuration-metadata.jsonrenamed toadditional-spring-configuration-metadata.json(overlay). Overlay values win for matching identities.8.0.x; generation now publishes bindable Markup Views properties.grails-web-coreintograils-web-url-mappingswithGrailsCorsConfiguration. Non-CORS web-core metadata stays hand-maintained ingrails-web-core.Generated defaults only include compile-time constants. Dynamic Groovy defaults are omitted unless an overlay supplies an authoritative value.
Compatibility check (against
origin/8.0.x)Re-verified on exact PR HEAD after regenerating metadata:
grails-web-core8.0.xfile)Each migrated jar contains exactly one standard metadata resource plus any curated additional metadata file.
Scope notes
@ConfigurationPropertiesmodules.DefaultSecurityConfig, generalapplication.groovymerging). Those remain later work.Verification
Local:
:grails-configuration-metadata:test+codeStyleConfigurationMetadataPluginSpec(clean, incremental, edit, delete, overlay, duplicate, immutable, generic-constructor safety)ConfigReportCommandSpec:grails-doc:publishGuide -x aggregateGroovydocCI on this PR: core builds (Linux/macOS), style/analysis/RAT/CodeQL/coverage, Forge, functional, security, Redis, MongoDB, and Hibernate suites are green. A few long jobs (Windows core, joint Groovy validation, selected functional reruns) were still finishing at description update time.
Commits
3-7. Per-module migrations (cache, databinding, gson, markup, URL mappings/CORS)
8-9. Docs reference inputs + guide prose
Stacked follow-up
#16048 is stacked on this PR and should be reviewed and merged afterward. It handles Groovy DSL parsing and the remaining in-repository metadata migrations tracked by #15469. This PR remains limited to the five existing
@ConfigurationPropertiesmodules and the shared generator correctness fixes required by its review; #16048 does not replace those fixes.