Great, thanks, saves me from doing it :-). The iss...
# groovy
v
Great, thanks, saves me from doing it :-). The issue says you can use
.@
to work-around. Is there also something similar for calling a private method? If not (or anyway) is there some way to doing something ad-hoc dynamically like
makeDynamic
in stc extension but in the actual code? Like
dynamic { foo.privateMethod() as String }
besides moving it to a helper method and marking that with
SKIP
I mean.
@paulk_asert <ping>
p
I haven't had a chance to properly think it through but here is what AI thinks:
Investigated both against the actual source and verified everything empirically on 6.0.0-beta-2. Here's what I found.
## Q1 — is there a
.@
equivalent for private methods?
Yes:
.&
— the method pointer.
```groovy
@CompileStatic
class T {
static void main(args) {
println (Q.&hidden)(3) // private static → 6
def q = new Q()
println (q.&inst)(3) // private instance → 103
def mp = Q.&hidden // storing it works too
}
}```
Same mechanism as `.@`: it sidesteps the static path.
.@
makes the compiler emit a direct field access instead of property resolution;
.&
produces a
MethodClosure
that dispatches through the metaclass at runtime, where Groovy's historic leniency about private access applies. Verified for static and instance private members, and with the declaring class written in both Groovy and Java.
::
is not an alternative — under STC a method reference resolves to a real target and visibility is enforced, so
Q::hidden
fails to compile. Only the dynamic
.&
form gets through.
Caveats: result type is
Object
, you're back on dynamic dispatch for that call, and it relies on
setAccessible
succeeding — it will break if the declaring class lives in a JPMS module that doesn't open the package.
The explicit spelling, if you'd rather not rely on a subtlety:
InvokerHelper.invokeMethod(foo, 'privateMethod', [a, b] as Object[])
(or
invokeStaticMethod
). Both compile under
@CompileStatic
and work.
## Q1b — an ad-hoc
dynamic { }
block?
No built-in, and a library method can't provide one:
@CompileDynamic
and
@TypeChecked
are
@Target([TYPE, METHOD, CONSTRUCTOR])
— no expression or local-variable scope — and a closure body written inside a
@CompileStatic
method is compiled statically along with it, so
dynamic { foo.privateMethod() }
can never work as a helper.
The closest inline form that avoids a named helper method is an anonymous inner class, since that gives you a method to annotate:
```groovy
def r = new Object() {
@CompileDynamic def call() { foo.privateMethod() }
}.call()```
Verified working. But it's ugly enough that the
@CompileDynamic
private helper is the better answer in practice.
## Q2 — will the fix bunch the reports?
Yes, and for a structural reason worth spelling out.
Access to P#M is forbidden
is emitted by
StaticTypesCallSiteWriter
during
CLASS_GENERATION
, not during type checking.
failIfErrors()
runs at the end of each phase, so one STC error anywhere in the whole compilation means codegen never runs and you see none of the access errors. Demonstrated:
```// two files, each with one bad private access AND one bogus method call
E1.groovy: 5: [Static type checking] - Cannot find matching method java.lang.Object#noSuchMethodHere()
E2.groovy: 5: [Static type checking] - Cannot find matching method java.lang.Object#alsoMissing()
2 errors ← the two P.M / P.N access errors are invisible```
So today it's a guaranteed two-round grind: round 1 gives STC errors, and only once those are entirely clean does round 2 reveal the access errors. Moving the check into STC — which is what GROOVY-12290 implies — puts them in the same batch. That's a decent secondary argument for the fix.
But that's probably not what's biting them. The cap is
CompilerConfiguration.tolerance
, default 10:
Copy code
14 bad accesses in one file  →  "10 errors"
And the no-arg
CompilerConfiguration()
hardcodes
tolerance = 10
— it does not read
groovy.errors.tolerance
(only the
Properties
-taking constructor does), so
-Dgroovy.errors.tolerance=50
on groovyc or Gradle is silently ignored. Confirmed. The working fix is a compiler configuration script, which they're already using anyway:
```groovy
configuration.tolerance = 100```
→
14 errors
instead of
10
.
Worth telling them explicitly: codegen errors do span files — I get 5 errors across 2 files in a single run. So "findings in one file per run" is the tolerance cap filling up on the first file (or an IDE/Gradle stopping early), not the compiler declining to continue.
For the tolerance side of things I created: issues.apache.org/jira/browse/GROOVY-12306
v
Hm, strange. That they are not in the STC batch, but in the class generation batch is expected. I first made all compile under STC, then switched on static compilation. But I really got only errors in one file at a time. Up to 10, yes, but sometimes also only one or two. But that is on Groovy 4, maybe that changed. The Groovy method closure trick I'll try, sounds promising, thanks.
and a closure body written inside a
@CompileStatic
method is compiled statically along with it, so
dynamic { foo.privateMethod() }
can never work as a helper.
How does
makeDynamic
in an STC extension work then? Or does that then makes the complete method dynamic? That would be a quite broad hit, and as far as I remember the docs did not suggest that. That's a quite dangerous thing to do if you actually want type-checked code. If that is the case, there should imho be a rather prominent warning in the docs where
makeDynamic
is described.
Btw. the
caModelBean.&init()
instead of
caModelBean.init()
to call private method workes like a charm, thanks.