Access GroovyScript fields in an anonymous class

In Groovy 2.1.6 Script, I define a field:

import groovy.transform.Field @Field String test = "abc"; println "Script: ${test}"; def run = new Runnable() { void run() { println "Runnable0: ${test}"; new Runnable() { void run() { println "Runnable1: ${test}"; } }.run(); } }.run(); 

When accessing it from anonymous classes in Script, for example here , Groovy seems to try to pass this field to the link and throws the following Exception as soon as Runnable is detected:

 org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'abc' with class 'java.lang.String' to class 'groovy.lang.Reference' at bug1.run(bug1:5) 

Also, if I put anonymous Runnables in a function, for example here , Groovy has no casting problems, but does not find the Field in the internal Runnable:

 groovy.lang.MissingFieldException: No such field: test for class: bug2$1 at bug2$1.this$dist$get$1(bug2.groovy) at bug2$1$2.propertyMissing(bug2.groovy) at bug2$1$2.run(bug2.groovy:14) at java_lang_Runnable$run.call(Unknown Source) at bug2$1.run(bug2.groovy:12) at java_lang_Runnable$run.call(Unknown Source) at bug2.fun(bug2.groovy:9) at bug2.run(bug2.groovy:5) 

This can be fixed by overriding the field, for example here , but this fix only works inside the function

Is this a mistake in Groovy, or am I just breaking some rules and Groovy lacks proper exceptions?

+4
source share
2 answers

You do not need to convert @Field in case you call an anonymous class and refer to a field variable.

Cause:
When a strongly typed variable in a script is defined as @Field , then this variable (at compile time [AST transformed]) is treated as confidential inside the script. Therefore, the property is absent.

To understand the difference, simply visualize the script in the AST browser from the Groovy console and go through the "Semantic Analysis" phase in both cases (without and with @Field), you will notice that the variable is local to run() for the main script compared to those defined otherwise otherwise .

The consequence :
On the other hand, the @Field conversion @Field useful when strongly typed variables must be used in a method inside the same script, because without @Field field will be declared as a local variable in the run() method of the script, therefore it is not visible to other methods.

Excerpts from AST browser for details.

+2
source

As Groovy Runnable closures, you can already do:

 import groovy.transform.Field @Field String test = "abc"; println "Script: ${test}"; { -> println "Runnable0: ${test}"; { -> println "Runnable1: ${test}" }.run() }.run() 

What works

0
source

Source: https://habr.com/ru/post/1501530/


All Articles