Domanda

In a Groovy 2.1.6 Script I'm defining 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 an anonymous Classes in the Script like here, Groovy seems to try to cast this Field to a Reference and throws the following Exception as soon as the Runnable is defined:

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)

Additionally, if i put the anonymous Runnables in a function like here, Groovy has no problems with casting, but doesn't find the Field in the inner 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 redefining the field like here , but this fix only works inside a function

Is this a bug in Groovy or am I just violating some rules and Groovy only lacks proper Exceptions?

È stato utile?

Soluzione

You do not need @Field transformation in case where you call anonymous class and refer the field variable.

Reason:
When a strictly typed variable in a script is defined as @Field then that variable (at compile time [AST transformed]) is treated as private inside that script. Hence property missing.

In order to realize the difference, just visualize the script in AST browser from Groovy console and go through the "Semantic Analysis" phase under both cases (without and with @Field), you would notice the variable is local to run() for the main script as compared to defined globally otherwise respectively.

Corollary:
On the other hand, @Field transformation is useful when strictly typed variables are to be used in a method inside the same script because without @Field the field will be declared as a local variable in the run() method of the script, hence not visible to other methods.

Excerpts from AST browser for details.

Altri suggerimenti

As Groovy closures are Runnables already, you could do:

import groovy.transform.Field
@Field String test = "abc";

println "Script: ${test}";
{ -> 
    println "Runnable0: ${test}";
    { -> 
        println "Runnable1: ${test}"
    }.run()
}.run()

Which works

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top