[
https://issues.apache.org/jira/browse/GROOVY-12569?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18134522#comment-18134522
]
ASF GitHub Bot commented on GROOVY-12569:
-----------------------------------------
codeconsole opened a new pull request, #3098:
URL: https://github.com/apache/groovy/pull/3098
A class that is not public is accessible only within its run-time package,
and the JVM checks that wherever an instruction names the class. Dynamic code
uses a package-private class of an earlier `GroovyShell` parse, or of a library
used by a script, without naming it. Statically compiled code named it and
failed with `IllegalAccessError`; it now does what dynamic code does, for
compilations that a `GroovyClassLoader` defines in memory:
```groovy
// first parse
package p
@PackageScope class Hidden implements Runnable { static String sm() { 'sm'
}; String name; String own() { 'own' }; void run() {} }
// second parse with the same GroovyShell (each line failed with
IllegalAccessError)
package p
@CompileStatic def test() {
def h = new Hidden(name: 'x')
h.run() // through Runnable
Runnable r = h
[Hidden.sm(), h.own(), h.name, [h]*.name]
}
```
`new`, also map-style with a literal or a `Map` variable, creates the object
through the meta-class; a static member of the class is used through the
meta-class; a method of the class is called through a public superclass or
interface that declares it, or else through the meta-class; a value of the
class is held as its nearest public superclass, so storing, passing or
assigning it to an interface type needs no cast to the class. A method pointer
keeps the class for method selection, and a method reference that would need a
method handle naming the class is a method closure, as in dynamic code. A
variable declared with the class, a cast to it and `instanceof` still fail, as
they do in dynamic code. Classes compiled to class files, classes of the same
compilation and public classes are named directly, as before.
This uses the run-time package rule of #3097
(`AsmClassGenerator.isInSameRuntimePackage`, the dynamic constructor call in
`StaticInvocationWriter`), and includes its commits until that is merged.
## Tests
`StaticCompileRuntimePackageTest`, marked `// GROOVY-12569`: each use of a
package-private class of another class loader, from a `GroovyShell` parse and
from a library defined by another class loader, compared with the same code
compiled dynamically; map-style construction; the uses that name the class fail
as in dynamic code; bytecode tests pin that no instruction names the class, and
that the class is named directly within the same compilation and in class files.
The `org.codehaus.groovy.classgen`, `org.codehaus.groovy.transform` and
`groovy.transform.stc` packages and `bugs` tests pass (6,387 tests);
`GenericsStaticCompileTest.testSelfReferentialTypeParameter5` failed once on
the `@Grab` race of GROOVY-12527 and passes when rerun. The Checkstyle and
CodeNarc gates pass.
> SC: a package-private class of another GroovyClassLoader compilation fails
> with IllegalAccessError where dynamic code works
> ---------------------------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12569
> URL: https://issues.apache.org/jira/browse/GROOVY-12569
> Project: Groovy
> Issue Type: Bug
> Components: Static compilation
> Affects Versions: 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> A class that is not public is accessible only within its run-time package
> (JVMS 5.4.4), and the JVM checks that wherever an instruction names the
> class. Dynamic code uses a package-private class of an earlier
> {{GroovyShell}} parse, or of a library used by a script, without naming it.
> Statically compiled code names it and fails:
> {code:groovy}
> def shell = new GroovyShell()
> shell.evaluate '''package p
> @groovy.transform.PackageScope class Hidden implements Runnable {
> static String sm() { 'sm' }
> String name
> String own() { 'own' }
> void run() { }
> }
> true
> '''
> shell.evaluate '''package p
> @groovy.transform.CompileStatic
> def test() {
> def h = new Hidden(name: 'x')
> h.run()
> Runnable r = h
> [Hidden.sm(), h.own(), h.name]
> }
> test()
> ''' // each line fails with IllegalAccessError; without @CompileStatic it
> works
> {code}
> Expected: as in dynamic code, {{new}} and static members go through the
> meta-class, a method is called through a public superclass or interface that
> declares it (else the meta-class), and a value of the class is held as its
> nearest public superclass. A variable declared with the class, a cast to it
> and {{instanceof}} still fail, as in dynamic code. Classes compiled to class
> files are used directly.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)