Groovy 5.0.x support for Grails 8 + Spring Boot 4#15557
Conversation
This reverts commit 457d6cd.
# Conflicts: # build.gradle # dependencies.gradle # grails-forge/build.gradle # grails-gradle/build.gradle
# Conflicts: # buildSrc/build.gradle # dependencies.gradle # grails-bootstrap/src/main/groovy/org/grails/config/NavigableMap.groovy # grails-gradle/buildSrc/build.gradle
# Conflicts: # dependencies.gradle # gradle/test-config.gradle # grails-forge/settings.gradle # settings.gradle
# Conflicts: # gradle.properties # grails-core/src/test/groovy/org/grails/plugins/BinaryPluginSpec.groovy
… + latest Jackson)
Cherry-picked comprehensive Groovy 5 compat from 9574fe8. Conflict resolutions: - dependencies.gradle: Groovy 5.0.5 GA (not SNAPSHOT) + Jackson 2.21.2 - LoggingTransformer: Keep manual log field injection (avoids Groovy 5 VariableScopeVisitor NPE entirely) - TransactionalTransformSpec: Remove direct Spock feature method invocation (Groovy 5/Spock 2.x incompatible) - grails-test-core/build.gradle: Remove spock-core transitive=false, keep junit-platform-suite - grails-test-suite-uber/build.gradle: Remove spock-core transitive=false and explicit byte-buddy
Removes workaround for Groovy 5 OptimizingStatementWriter slow-path bug for parameterized controller actions. Groovy issue https://issues.apache.org/jira/browse/GROOVY-12062 fixed by apache/groovy#2590 upstream.
|
GROOVY-12062, Controller-action parameter scope under indy=false, now fixed at the source, workaround removed. |
jdaugherty
left a comment
There was a problem hiding this comment.
I went over all of these changes, and these are the outstanding issues:
- Need clarification on this one: https://github.com/apache/grails-core/pull/15557/files#r3341502124 (are we just calling these wrong?)
- the changes to GroovyChangeLogSpec can be reverted
- HibernateEntityTraitGeneratedSpec has a regression (wrong method being tested)
- null exception issue - https://github.com/apache/grails-core/pull/15557/files#r3341529954
- odd trait behavior - https://github.com/apache/grails-core/pull/15557/files#r3341533083
- static trait issue - https://github.com/apache/grails-core/pull/15557/files#r3341541233
- static gsp regression - https://github.com/apache/grails-core/pull/15557/files#r3341559619
- needs tested - https://github.com/apache/grails-core/pull/15557/files#r3341563931
- Sortable & entity compile issue - https://github.com/apache/grails-core/pull/15557/files#r3341626756
- Object is no longer assignable to ? - https://github.com/apache/grails-core/pull/15557/files#r3341642950
| } | ||
|
|
||
| // Note: In Groovy 5, the type checking extension behavior changed and undeclared variables | ||
| // in GSP templates may not trigger compilation errors. This is a known limitation. |
There was a problem hiding this comment.
Yes, the whole point of CompileStatic is to fail on unresolveable properties. This still seems like a regression. The taglib support is separate from this.
Use Groovy's LogASTTransformation again for the injected Slf4j logger so Grails follows the standard Groovy logging transform path. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Assisted-by: Hephaestus:openai/gpt-5.5 oracle
Normalize generated MethodNode exception arrays to empty arrays so Groovy 5 VariableScopeVisitor never sees null exceptions. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Assisted-by: Hephaestus:openai/gpt-5.5 oracle
Remove stale workaround comments and point the GSP Groovy 5 skip at the tracked upstream issue. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Assisted-by: Hephaestus:openai/gpt-5.5 oracle
Keep the validation message map immutable while preserving the GROOVY-12063 workaround and document the still-active trait and sortable regressions. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Assisted-by: Hephaestus:openai/gpt-5.5 oracle
Check generated HibernateEntity methods on the declaring class and avoid environment-dependent Liquibase log output assertions. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Assisted-by: Hephaestus:openai/gpt-5.5 oracle
Use Renderer<?> for default view renderer fallbacks so CompileStatic sees the generic renderer contract without changing erased constructor signatures. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Assisted-by: Hephaestus:openai/gpt-5.5 oracle
|
Pushed the latest cleanup as six focused commits through 308c451. Addressed and resolved the concrete review items for redundant comments, Hibernate generated-method checks, dbmigration log assertions, MethodNode exception arrays, DEFAULT_MESSAGES immutability, LoggingTransformer Slf4j handling, and the active Groovy 5 guard comments. I left two conversations open intentionally because they remain upstream/reviewer-decision topics rather than completed code changes: the Groovy 5 GSP unresolved-property STC regression and the Groovy 5 wildcard assignment question in DefaultViewRenderer. |
308c451 to
7c1bae7
Compare
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Assisted-by: Hephaestus:openai/gpt-5.5
Last-24h update: review burn-down + base alignmentDescription refreshed to match the current tree. Quick map of the commits since yesterday and the review threads each one closes out. Base alignment (via merge)
Review feedback addressed
Workaround removed (snapshot caught up)
Still open (double-checked against the snapshot)The two JIRA-tracked workarounds remain because both tickets are still Open and still reproduce on
GROOVY-12041 (open) also still affects the |
- In Groovy 5, the exceptions parameter cannot be null. - Use ClassNode.EMPTY_ARRAY and Parameter.EMPTY_ARRAY consistently when creating methods.
Keep the Spring Dependency Management regression example aligned with the source tree's Groovy and Spock BOM properties when importing the Grails BOM. This prevents the example from resolving stale published snapshot metadata while local Grails modules are compiled against the current Groovy line. Assisted-by: opencode:openai/gpt-5.5 oracle
Fixes a regression in `grails-fields` FormFieldsTagLib, where page-scope bean names were being resolved through a binding map lookup that no longer behaved the same with Groovy 5. The fix normalizes lookup keys to String before accessing `pageScope.variables`, and a regression test was added in `RequiredAttributesSpec`.
The previous change was the result of a problem with the TestLens GitHub CI app/addon. After this was resolved upstream, the change is no longer necessary.
|
Groovy Jira ticket created for |
Aligns with Groovy bump upstream
|
Groovy Jira Ticket for "bounded generic trait property generates unimplemented abstract setter" issue in |
✅ All tests passed ✅🏷️ Commit: 3842442 Learn more about TestLens at testlens.app. |
Adds Apache Groovy 5.0.x support on top of
8.0.x, tracking5.0.7-SNAPSHOTfromGROOVY_5_0_X. Verified on JDK 21 under bothindy=trueand-PgrailsIndy=false.Most of the diff is adapting to Groovy 5's stricter
@CompileStatictype checking and a few API/behaviour changes (MetaClassHelper.capitalizeremoval,Filetruthiness, etc.). The areas worth a closer review are below.Target stack
GROOVY_5_0_X)AST-level fixes
VariableScopeVisitorNPE. Groovy 5'sVariableScopeVisitor.visitConstructorOrMethodreads the method exceptions array without a null check, so it NPEs on methods created viaClassNode.addMethod(..., null, ...). Per review feedback that the correct fix is to populate the exceptions at the creation site rather than post-process them, Grails AST transforms now construct those method nodes withClassNode.EMPTY_ARRAYinstead ofnull(ServiceTransformation,ResourceTransform). A defensive proxy-MethodNodefallback remains at theprocessVariableScopeschokepoints (GrailsASTUtils,AstUtils) for the remaining nodes (e.g. the renamed node fromAbstractMethodDecoratingTransformation) and any foreign null-exception methods we do not create. Reproducer: groovy5-variablescope-canonicalization-bug.setVariableScope(new VariableScope())inResourceTransform/AbstractMethodDecoratingTransformationfixes a synthesised-ClosureExpressionnull-scopeClosureWriterNPE. This is an all-version fix (it also reproduces on Groovy 4.0.31), not Groovy-5-specific.LoggingTransformeragain drives Groovy's ownLogASTTransformationto inject thelogfield (rather than hand-building theLoggerFactory.getLogger(...)field), so Grails follows the standard Groovy logging-transform path.Workarounds for open upstream Groovy bugs
Each works around an unfixed Groovy 5 defect (verified still failing on
5.0.7-SNAPSHOT) and can be removed once the upstream fix lands inGROOVY_5_0_X.ConstrainedProperty.DEFAULT_MESSAGESis built from a Groovy map literal (then wrapped immutable) instead of an anonymous-HashMap-with-instance-initialiserDEFAULT_*_MESSAGEconstants inside such an initialiser compile to dynamicgetPropertyreads onthis(theHashMap); because the receiver is aMap, the MOP resolves them as key lookups on the still-empty map, so every entry was captured asnull. A map literal resolves the constants against the enclosing interface scope and is correct on every version.DefaultMessageResolutionSpecValidateable.resolveDefaultNullable()/BeanPropertyAccessorFactoryuseMethod.invokereflectionTraitReceiverTransformerrewrites the in-traitthis.defaultNullable()call to a direct trait-helper static call, losing the implementing-class override; reflection is the only path that honours it.The
g.taglibSTC change (GroovyPageTypeCheckingExtension) matches the taglib namespace by name inmethodNotFound- the approach @paulk-asert recommended for GROOVY-12041 (open) - because when the receiver inheritsgetProperty(String)the STCunresolvedVariable/unresolvedPropertycallbacks never fire. Static compilation ofg.*taglib calls works; the only loss is the negative (undeclared-variable) check - see the table below. Reproducer: groovy5-stc-extension-node-identity-bug.Worked around without a clean fix (flagged in review)
Items @jdaugherty flagged where a clean fix was not available, so the Groovy 5 behaviour is worked around. These are deliberately left as-is with the rationale below; none has a published upstream fix.
GspCompileStaticSpecundeclared-variable specs@CompileStaticis to fail on unresolvable properties - this still seems like a regression."@IgnoreIf({ groovy5 })skips on the negative (undeclared-variable) assertions only;g.*taglib resolution itself works via the name-matching extension.GrailsWebDataBinderSpec@Entityfixtures@Sortable+@Entitydon't generate the same method, this is a Groovy bug we need to understand."compareTo/Comparablereplaces@Sortablein the two test fixtures (the combination NPEs in canonicalization).ClassPropertyFetcherTests.TestTraitfromis public and should be copied to implementers - why does it fail only withSerializable? Likely a Groovy bug."<F extends Serializable>to<T>; the domain stillimplements Serializable, so the datastore behaviour under test is unchanged.GrailsASTUtils/AstUtilsprocessVariableScopesEMPTY_ARRAY); a proxy-MethodNodefallback is retained only for foreign null-exception nodes we don't create.addMethodto rejectnullTransactionalTransformSpec$tt__invocation assertions dropped; generation still verified viagetDeclaredMethodsignature checks.Related PRs (target
8.0.x)2.4alignment on the8.0.xline.org.ow2.asm9.10.1-vs-9.9.1 BOM version conflict inherited from base.@GrailsCompileStaticsupport for controllers that call tag libsg.taglibSTC change.javaparser-coreBOM entry.