Groovy Scripts - Exploring Binding
In a previous post exploring scripting basics, we saw how binding
was used to supply command-line arguments to scripts. In this post, let's explore the design of binding further.
class BindingDemo {
static void main(String[] args) {
Binding sampleBinding = new Binding()
println sampleBinding.variables
sampleBinding.message = "Hello"
println sampleBinding.variables
println sampleBinding.message
}
}
Let's run the code.
➜ groovy BindingDemo.groovy
[:]
[message:Hello]
Hello
In the above code, we start by creating an instance of groovy.lang.Binding
. At this moment, we see sampleBinding.variables
is an empty map. Adding values to binding is achieved using the dot operator. It would look similar to setting a value into a map.
If you already have your values in a map, you could invoke the constructor of Binding
by passing the map instance as follows.
Binding bindingFromMap = new Binding([one: 1, two: 2])
bindingFromMap.three = 3
println bindingFromMap.variables // [one:1, two:2, three:3]
If you invoke the constructor with an argument of type array, the value is stored under the key 'arguments'. This technique is used to pass command-line arguments to scripts.
Binding bindingWithArgs = new Binding(['first', 'second'] as String[])
println bindingWithArgs.variables // [args:[first, second]]
To understand the use of binding in a script, let's create a class by extending groovy.lang.Script
as follows.
@InheritConstructors
class SampleScript extends Script {
@Override
def run() {
println message
}
}
class BindingDemo {
static void main(String[] args) {
Script script = new SampleScript(new Binding([message: 'Hello']))
script.run()
}
}
In the above code, neither there is a local variable named message
inside the run
method, nor there is an instance variable named message
. Hence Groovy will lookup for message
in the binding object of the script. Since we have a value for message
, it will be made available, and the program would print "Hello".
In the usual scenarios, we would invoke the script using groovy
command, which would take care of generating the SampleScript
class. As an added advantage, you could also read and evaluate the script from a running Groovy application. To demonstrate this, let's create a script file named sample.script
under '/Users/naresha/temp' directory.
sample.script
println message
Now let's read the file 'sample.script' from our applicationBindingDemo
and execute the script with the existing binding context as follows.
class BindingDemo {
static void main(String[] args) {
Script script = new SampleScript(new Binding([message: 'Hello']))
script.run()
// Running a dynamically loaded script
File scriptFile = new File('/Users/naresha/temp/sample.script')
script.run(scriptFile, [] as String[])
}
}
Without the binding, we could not have passed a context into the script we loaded and evaluated at the runtime, and it would have severely limited what we could achieve with the scripts. With the availability of binding, developers get to pass the context information to scripts which they can even load at the runtime.
I have used Groovy version 3.0.5 in this post.