I am writing a Groovy script, where I need to use some of my fields inside closures. Below is a very simplified example to demonstrate my problem.
#!/usr/bin/env groovy
import groovy.transform.Field
@Field def first = 'one'
assert first == 'one'
So far so good. In my real-world case, this will hold a String representing a server name. I then modify this "default" value from command-line options - using CliBuilder() - maybe something like:
first = 'two'
assert first == 'two'
This still works. I now need to create a new field, from the one above:
@Field def second = first
assert second == 'two'
In my real-world case, this will be an HTTPBuilder() that I will be making REST calls with.
This fails:
Assertion failed:
assert second == 'two'
| |
'one' false
Is there a way to get this to work?
A failed attempt to somehow work around this. Using an intermediary, something like:
def intermediary = first
assert intermediary == 'two'
@Field def second = intermediary
Fails with:
Caught: java.lang.reflect.InvocationTargetException
java.lang.reflect.InvocationTargetException
at something.main(something)
Caused by: groovy.lang.MissingPropertyException: No such property: intermediary for class: something
at something.<init>(something)
... 1 more
the annotation @Field
declares member of the script class and any other script commands will go to script.run()
method
for example the script
import groovy.transform.Field
@Field def first = 'one'
first = 'two'
@Field def second = first
assert second == 'two' // <<<---- fails because second=='one'
will be transformed approximately to this class during script compilation:
class scriptXXXX{
Object first
Object second
scriptXXXX(){ // constructor
first = 'one'
second = first
}
void run(){ // script body
first = 'two'
assert second == 'two' : null
}
}
You could see this in groovyconsole
by pressing Ctrl+T
as a variant you could separate field declaration and initialization:
@Field def first = 'one'
@Field def second
first = 'two'
second = first
assert second == 'two'