G
YouTube TikTok Games
Skip to content

GROOVY-12718: use a package-private field of another run-time package through the meta-class in dynamic code - #3252

Open
codeconsole wants to merge 6 commits into
apache:masterfrom
codeconsole:dyn-field-other-runtime-package
Open

codeconsole wants to merge 6 commits into
apache:masterfrom
codeconsole:dyn-field-other-runtime-package

Conversation

@codeconsole

@codeconsole codeconsole commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

In dynamic and @TypeChecked code, a package-private field of a superclass with the same package name but of another class loader, such as a class of an earlier parse of the same GroovyShell, is reached through the meta-class by f and this.f. The forms that go directly to the field fail:

// first parse
package p
class F { @PackageScope String pf = 'pf' }

// second parse with the same GroovyShell
package p
class C extends F {
    def test() {
        super.pf            // IllegalAccessError, as are super.@pf and this.@pf
        this.@pf = 'w'      // and writes through them
    }
}

4.0.32, 5.0.8 and 6.0.0 fail the same way. AsmClassGenerator.visitPropertyExpression and visitAttributeExpression decide by the package name and write GETFIELD or PUTFIELD. They now leave such a field to the meta-class in dynamic code, using isInSameRuntimePackage, which only knows the case for an in-memory compilation of a GroovyClassLoader.

Static compilation is unchanged: it does not select a member at run time. #3097 (GROOVY-12568) reports such an access there. A protected field, which a subclass can use directly, and a field of the same compilation are still accessed directly.

This and #3097 add an import next to each other in AsmClassGenerator; whichever lands second keeps both.

Compatibility

Code that failed with IllegalAccessError now works.

Tests

bugs.Groovy12718: testReadOfPackagePrivateFieldOfSuperclass and testWriteOfPackagePrivateFieldOfSuperclass, each dynamic and @TypeChecked, fail without the change. The other tests pin what must not change: closures, a protected field and a field of the same compilation stay as they are, and static compilation still fails at run time without #3097. The org.codehaus.groovy.classgen.asm.sc, groovy.transform.stc and gls tests pass, apart from the two testSelfReferentialTypeParameter5 tests, whose @Grab of netty did not resolve on my network. The Checkstyle and CodeNarc gates pass.

… through the meta-class in dynamic code

In dynamic and @TypeChecked code, super.f, super.@f and this.@f of a
package-private field of a superclass with the same package name compile to
a direct field access. For a superclass of another run-time package, such as
a class of an earlier parse of the same GroovyShell, the JVM refuses that with
IllegalAccessError, although a plain f or this.f reaches the field through the
meta-class.

These forms now do the same for such a field. Static compilation does not
select a member at run time, so it is unchanged.
@codecov-commenter

codecov-commenter commented Nov 7, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 74.4595%. Comparing base (97e0f72) to head (074d51e).

Files with missing lines Patch % Lines
...rg/codehaus/groovy/classgen/AsmClassGenerator.java 80.0000% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##               master      #3252        +/-   ##
==================================================
+ Coverage     74.4524%   74.4595%   +0.0071%     
- Complexity      44845      44852         +7     
==================================================
  Files            1702       1702                
  Lines          151995     151998         +3     
  Branches        29122      29124         +2     
==================================================
+ Hits           113164     113177        +13     
+ Misses          28422      28410        -12     
- Partials        10409      10411         +2     
Files with missing lines Coverage Δ
...rg/codehaus/groovy/classgen/AsmClassGenerator.java 86.0876% <80.0000%> (+0.0295%) ⬆️

... and 14 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@daniellansun daniellansun left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct fix for GROOVY-12718.

Package name equality is not run-time package equality (package + ClassLoader). Dynamic / @TypeChecked code that wrote GETFIELD/PUTFIELD for a package-private superclass field from another GCL parse therefore hit IllegalAccessError, while plain f / this.f already went through the meta-class. Routing such access through the meta-class via isDynamicAccessOfAnotherRuntimePackage (and skipping the rewrite under StaticInvocationWriter) matches the JVM rule and leaves SC unchanged — as #3097 reports there.

DynamicFieldOfAnotherRuntimePackageTest covers reads/writes, attribute forms, closures, protected-still-direct, same-compilation-still-direct, and SC still throwing IllegalAccessError — good matrix.

Please before approve:

  1. CI: lts (17, ubuntu-latest) failed on :groovy-dateutil:test with Could not read path '.../resolved-caller-all-caller-working69.xml' — grape/cache infra, unrelated to AsmClassGenerator. Windows/macOS and the other Ubuntu LTS cells are green; please re-run that cell.

Happy to APPROVE once Ubuntu is re-run green (or confirmed flake). Depends conceptually on the runtime-package helpers from #3097.

@codeconsole

Copy link
Copy Markdown
Contributor Author

@daniellansun I can't re-run jobs on apache/groovy, so I merged current master (492ae79) to get a fresh run. lts (17, ubuntu-latest) failed on :groovy-dateutil:test reading the grape cache. No code changes; DynamicFieldOfAnotherRuntimePackageTest passes locally on the merge.

As CONTRIBUTING asks for a standalone regression test class, it is
bugs.Groovy12718.
The two tests compiled with a plain CompilationUnit, whose classes are
not defined in memory, so every class is in the same run-time package
there and the tests could not tell what they are named for. They now
compile with a GroovyClassLoader, as a GroovyShell does: the protected
field is of a superclass of an earlier compilation, and the
package-private field is of the same in-memory compilation.
GroovyShell turns on the compile-time check of the run-time package that
GROOVY-12568 adds, which reports this access before it runs. The test
compiles with a GroovyClassLoader of its own instead, so it shows the
unchanged IllegalAccessError whether or not that check is present.
…time-package

# Conflicts:
#	src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@testlens-app

testlens-app Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

🚨 All tests passed but jobs failed 🚨

Failed Jobs without Test Failures

❌ Lint gate / lint

🏷️ Commit: 074d51e
▶️ Tests: 128599 executed
⚪️ Checks: 26/26 completed

Rerun Controls

Click the checkbox to trigger a rerun:

  • Rerun jobs

Learn more about TestLens at testlens.app/docs.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants