jamesfredley commented on PR #15558:
URL: https://github.com/apache/grails-core/pull/15558#issuecomment-4577971891

   ## Blocker #6 resolved - Groovy 6 Verifier abstract-method regression worked 
around (`8b349bcdb8`)
   
   After re-baselining the canary on the updated `grails8-groovy5-sb4` (merge 
`3538600648`, which brings in the GROOVY-12040 `@Builder` removal), 
`:grails-views-gson:compileGroovy` was the **sole** remaining failure - the 
entire rest of the dependency chain compiles. It is now fixed.
   
   ### Root cause (confirmed)
   
   The diagnostic comes from 
`org.codehaus.groovy.classgen.ClassCompletionVerifier.checkNoAbstractMethodsNonAbstractClass`,
 which iterates `ClassNode.getAbstractMethods()` built from 
`getDeclaredMethodsMap()`, keyed by `MethodNode.getTypeDescriptor()` - and the 
descriptor **includes the return type**. On Groovy 6 the concrete leaf 
`render(...)` overrides in `DefaultGrailsJsonViewHelper` resolve a *different* 
descriptor for the inner-class return type 
`grails.plugin.json.builder.JsonOutput.JsonWritable` than the abstract 
`render(...)` entries inherited from the `GrailsJsonViewHelper` interface, so 
they never displace the abstract entries, which then survive and are reported 
"unimplemented" - for all 5 overloads, including the two declared explicitly.
   
   A key catalyst: **`groovy.json.JsonOutput.JsonWritable` was removed in 
Groovy 6** (the class now declares only `JsonUnescaped`). The Grails 
`JsonOutput.JsonWritable` shadowed it on Groovy 5; on Groovy 6 there is nothing 
to shadow, which changes how the inner-class return type resolves. This is a 
Verifier-layer defect, not the static type checker - it reproduces with 
`@CompileStatic` removed.
   
   ### The fix (workaround #12, the first that works)
   
   Declare the 5 `GrailsJsonViewHelper#render(...)` methods as **`default`** 
(concrete, throwing `UnsupportedOperationException`). Because the bug is 
specifically in the *abstract*-method check, making the methods non-abstract 
removes them from `getAbstractMethods()` entirely - the verifier has nothing to 
flag. `DefaultGrailsJsonViewHelper` is the **sole implementor** and overrides 
all 5, so the throwing default bodies are never reached.
   
   The twelve earlier attempts that did **not** work (this PR's 
[workaround-attempts 
comment](https://github.com/apache/grails-core/pull/15558#issuecomment-4523762826)
 lists the first ten): explicit forwarders, fully-qualified return types, 
inner-class rename, removing `@CompileStatic` from class and interface, 
explicit constructor, abstract-parent + concrete-subclass, `@CompileDynamic`, 
diamond removal, diamond + covariant-`getG` removal, and - new this round - 
concrete `render` stubs on the intermediate superclass `DefaultJsonViewHelper` 
(Oracle's first suggestion; it failed because the stub gets the same mismatched 
descriptor).
   
   ### Verification (Groovy 6.0.0-SNAPSHOT build #716 / Gradle 9.5.1 / Spring 
Boot 4.0.6, JDK 21)
   
   | Task | Result |
   |---|---|
   | `:grails-views-gson:compileGroovy` | green |
   | `:grails-views-gson:test` | all pass (render / HAL / JSON-API / 
template-inheritance incl. `g.render(..)`); 1 pre-existing `@IgnoreIf` skip |
   | `:grails-views-gson:codeStyle` | green |
   
   The render-path tests exercise the real implementations, confirming the 
`default` bodies are never hit at runtime.
   
   ### Standalone reproducer status
   
   I built a faithful structural mirror (`repro6b`): a Java outer class 
extending `groovy.json.JsonOutput` with a shadowing inner `JsonWritable`, the 
`@CompileStatic` interface chain `JsonViewHelper extends ViewHelper extends 
LinkGen`, the diamond (`DefaultJsonViewHelperBase extends DefaultViewHelper 
implements ViewHelper`; `Impl extends ... implements JsonViewHelper`), 
default-argument `render`, mixed `void inline(...)`, joint Java+Groovy 
compilation, precompiled-jar split, and anonymous `JsonWritable` subclass 
instances. **It compiles cleanly** on build #716 - i.e. none of those 
ingredients in isolation trigger the defect (matching the earlier finding). The 
real `grails-views-gson` module remains the working in-tree reproducer; 
isolating the last differentiating element into a dependency-free case is still 
open and will accompany the upstream Apache Groovy ticket.
   
   ### Net
   
   The canary now builds, tests, and style-checks end-to-end on build #716; the 
only remaining non-production crutch is the Spock `disableGroovyVersionCheck` 
bridge (still DRAFT/DO-NOT-MERGE until a Spock `*-groovy-6.0` artifact ships). 
Inherited workarounds are unchanged (#1 Validateable / GROOVY-11985, #2 
VariableScopeVisitor canonicalization, #3 
boot4-disabled-integration-test-config, #4 AbstractConstraint static-init).
   
   Assisted-by: claude-code:claude-4.8-opus
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to