jamesfredley commented on PR #15558: URL: https://github.com/apache/grails-core/pull/15558#issuecomment-4523762826
## Groovy 6 Verifier regression on `grails-views-gson:compileGroovy` - investigation summary The merge brought the canary forward past the previously-blocking `grails-data-graphql-core:compileGroovy` failure (now resolved on `sb4` and rolled up in `7156ed8e3a`). The next failure that surfaces is a brand-new Groovy 6 Verifier regression in `grails-views-gson` that does **not** exist on Groovy 5. ### Confirmation: same source, two outcomes The file `grails-views-gson/src/main/groovy/grails/plugin/json/view/api/internal/DefaultGrailsJsonViewHelper.groovy` is **bit-identical** between `grails8-groovy5-sb4` (`68fe246bef`, latest sb4 commit) and `grails8-groovy6-canary` (HEAD): ``` SHA256 sb4 = 83272A2B5083578D96B8E653ED4310DAEB17CDD13AA5E2E4C1EF9D49DAFE1C9B SHA256 canary = 83272A2B5083578D96B8E653ED4310DAEB17CDD13AA5E2E4C1EF9D49DAFE1C9B ``` - sb4 (Groovy 5.0.7-SNAPSHOT): `Build Grails-Core` PASS on `68fe246bef`. - canary (Groovy 6.0.0-SNAPSHOT build #700): `:grails-views-gson:compileGroovy` FAIL with 5 abstract-method-implementation errors on `DefaultGrailsJsonViewHelper.groovy:67`, one per `render(...)` overload from `GrailsJsonViewHelper`. ### The actual error ``` Can't have an abstract method in a non-abstract class. The class 'grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper' must be declared abstract or the method 'grails.plugin.json.builder.JsonOutput$JsonWritable render(java.util.Map)' must be implemented. ``` 5 errors, one per overload: `render(Map)`, `render(Object, Map, Closure)`, `render(Object, Map)`, `render(Object)`, `render(Object, Closure)`. All 5 methods are declared explicitly on the class with matching signatures. They are also reachable via the `render(Object, Map = ..., Closure = ...)` default-argument form at line 348. Groovy 6 ignores both forms and reports them as unimplemented. ### Fresh-cache confirmation Tested against `org.apache.groovy:groovy:6.0.0-SNAPSHOT` build #700 (`6.0.0-20260522.234755-700`) after wiping `~/.gradle/caches/modules-2/files-2.1/org.apache.groovy` and re-running with `--refresh-dependencies --rerun-tasks`. The freshly-downloaded jar resolved to the maven-metadata.xml-published build #700 (latest as of 2026-05-22 23:47 UTC). Bug reproduces unchanged. None of the 12 apache/groovy master commits since 2026-05-20 (`a2ce6f02..3cbd88c4a5`) touch the Verifier or `@CompileStatic` abstract-method-implementation path. ### Workaround attempts (all REJECTED) | # | Attempt | Result | |---|---|---| | 1 | Add 5 explicit `@Override` `render(...)` forwarders for the default-arg form | Same 5 errors | | 2 | Fully qualify return type to `grails.plugin.json.builder.JsonOutput.JsonWritable` at every site | Same 5 errors | | 3 | Rename the inner class `JsonOutput.JsonWritable` -> `JsonOutput.GrailsJsonWritable` (eliminates the name shadowing with `groovy.json.JsonOutput.JsonWritable`) | Same 5 errors with the renamed type | | 4 | Remove `@CompileStatic` from `DefaultGrailsJsonViewHelper` | Same 5 errors. **Confirms the bug is at the Verifier layer, not the STC.** | | 5 | Remove `@CompileStatic` from `GrailsJsonViewHelper` interface | Same 5 errors | | 6 | Replace `@InheritConstructors` with an explicit `DefaultGrailsJsonViewHelper(GrailsView)` constructor | Same 5 errors when other annotations are also present | | 7 | Mark `DefaultGrailsJsonViewHelper` abstract + create concrete subclass `ConcreteGrailsJsonViewHelper extends DefaultGrailsJsonViewHelper` | Suppresses bug on the abstract parent but fires identically on the concrete subclass - the Verifier check is per-class | | 8 | Mark the concrete subclass `@CompileDynamic` | Same 5 errors. **Confirms the bug ignores `@CompileDynamic`.** | | 9 | Remove `extends GrailsViewHelper` from `GrailsJsonViewHelper` (breaks the diamond inheritance of `GrailsViewHelper` between the parent class chain and the interface chain) | **Only superficially suppresses** the bug. The build then halts on 2 STC errors in `DefaultHalViewHelper` (`viewHelper.link(Map)` is no longer reachable through the interface). Once those are fixed (e.g. via `((GrailsViewHelper) viewHelper).link(...)` casts), the abstract-method bug re-fires on `DefaultGrailsJsonViewHelper`. The diamond-removal does not actually fix anything - it just delays the bug until the build progresses past the link calls. | | 10 | All of #9 PLUS remove the covariant `getG()` override from the `JsonView` trait (so it inherits the parent trait's `GrailsViewHelper getG()`) | Same outcome as #9 - bug re-fires once the build progresses | ### Annotation-isolation matrix With every other change reverted to baseline and one annotation at a time on the class header: | Class annotations | Result | |---|---| | `@CompileStatic @InheritConstructors @Slf4j` (original) | 5 errors | | `@InheritConstructors @Slf4j` (no `@CompileStatic`) | 5 errors | | `@CompileStatic @Slf4j` + explicit constructor | 5 errors | | `@CompileStatic` alone + explicit constructor | 2 STC errors (unrelated `log` undeclared - confirms abstract-method bug is gone with `@Slf4j` removed) | | `@Slf4j` alone + explicit constructor | 5 errors | | `@InheritConstructors` alone | 5 errors | | No annotations + explicit constructor | 5 errors | | No annotations, no explicit constructor | 1 error (missing constructor - compile aborts before the abstract-method check fires) | The matrix shows the abstract-method check fires **on every class configuration that can compile far enough to reach the check**. The bug is not gated by any annotation or transform - it is a fundamental Verifier defect for this inheritance shape on Groovy 6. ### Minimal-reproducer status Saved at `groovy6-inner-abstract-class-stc-bug/` (will push to a public repo for upstream filing). The reproducer mirrors the structural pattern: - Java outer class with inner abstract class shadowing the parent's inner class (`reproducer.JsonOutput.JsonWritable` shadowing `groovy.json.JsonOutput.JsonWritable`) - `@CompileStatic` interface chain `MyInterface extends ParentInterface extends LinkGenerator` with 5 `render(...)` overloads returning the inner abstract class - Concrete class `@CompileStatic @InheritConstructors MyImpl extends MyIntermediateBase extends MyBase implements MyInterface, ParentInterface` (diamond) **The reproducer compiles cleanly on Groovy 6.0.0-SNAPSHOT build #700.** Some additional element of the real `grails-views-gson` codebase is required to trigger the Verifier path; I have not isolated it yet. The grails-views-gson source itself is the working reproducer for now (open source, fully self-contained module). ### Recommendation Three paths forward, none ideal: 1. **File the upstream ticket** with grails-views-gson itself as the reproducer; track as workaround #6 (blocked, upstream-only) until the Groovy 6 release picks up the fix. CI stays red on this matrix entry. 2. **Pin the canary** to an older Groovy 6 snapshot if there is a build prior to whichever one introduced the regression; needs a git-bisect across `apache/groovy` to find the offending commit. 3. **Disable `:grails-views-gson:compileGroovy`** on the canary as a known-failing-quarantine entry. Loses regression coverage. Happy to take direction on any of these. The four CI fixes in `7156ed8e3a` (`[email protected]` license, `asm 9.10` BOM overrides, `TemplateRenderer` 5 forwarders, `BeanPropertyAccessorImpl @MapConstructor`) are mechanical and stand on their own; they remove 3 of the 4 distinct CI failure categories the canary was hitting before the merge. -- 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]
