Understand Bindings and Scopes
Behind the scenes, ScriptEngine's put() and get() methods store state into and retrieve state from a bindings object, which is an instance of a class that implements the Bindings interface—the SimpleBindings class is an example. Because Bindings extends java.util.Map
A bindings object is associated with a scope, which is the visibility that the bindings object's key/value entries have to the script engines. The Scripting API currently defines global and engine scopes:
- The entries in a bindings object with global scope are visible to all script engines.
- The entries in a bindings object with engine scope are visible only to the script engine to which the bindings object is associated.
The ScriptEngineManager class creates the initial global bindings. It also provides a public void setBindings(Bindings bindings) method that can be invoked to replace the global bindings, and a public Bindings getBindings() method for retrieving the global bindings. Furthermore, ScriptEngineManager provides public void put(String key, Object value) and public Object get(String key) methods for storing state into and retrieving state from the global bindings.
In addition to the engine-oriented put() and get() methods, ScriptEngine provides a public void setBindings(Bindings bindings, int scope) method for installing new global or engine bindings (scope is either one of ScriptContext.ENGINE_SCOPE or ScriptContext.GLOBAL_SCOPE). ScriptEngine also provides a complementary public Bindings getBindings(int scope) method for returning scope's bindings object.
It is possible to replace an engine's current bindings object with a new bindings object prior to evaluating a script, and then restore the original bindings object following one or more script evaluations. You might do this when you want to leave the contents of the current bindings object unaffected by the script. The following steps accomplish this task:
- Obtain the current bindings object by calling ScriptEngine's getBindings(int scope) method with scope set to ScriptContext.ENGINE_SCOPE. Save this object's reference.
- Create a new uninitialized bindings object via ScriptEngine's public Bindings createBindings() method.
- Install the new bindings object by calling ScriptEngine's setBindings(Bindings bindings, int scope) method, with scope set to ScriptContext.ENGINE_SCOPE.
- Set state and evaluate the script.
- Restore the previous saved bindings via setBindings().
Listing 4 presents a simple application that demonstrates replacing a script engine's bindings.
Listing 4: ScriptDemo4.java
// ScriptDemo4.java import javax.script.*; public class ScriptDemo4 { public static void main (String [] args) throws ScriptException { // Create a ScriptEngineManager that discovers all script engine // factories (and their associated script engines) that are visible to // the current thread's classloader. ScriptEngineManager manager = new ScriptEngineManager (); // Obtain a ScriptEngine that supports the JavaScript short name. ScriptEngine engine = manager.getEngineByName ("JavaScript"); // Initialize the color and shape script variables. engine.put ("color", "red"); engine.put ("shape", "rectangle"); // Evaluate a script that outputs the values of these variables. engine.eval ("println (color); println (shape);"); // Save the current bindings object. Bindings oldBindings = engine.getBindings (ScriptContext.ENGINE_SCOPE); // Replace the bindings with a new bindings that overrides color and // shape. Bindings newBindings = engine.createBindings (); newBindings.put ("color", "blue"); engine.setBindings (newBindings, ScriptContext.ENGINE_SCOPE); engine.put ("shape", "triangle"); // Evaluate the script. engine.eval ("println (color); println (shape);"); // Restore the original bindings. engine.setBindings (oldBindings, ScriptContext.ENGINE_SCOPE); // Evaluate the script. engine.eval ("println (color); println (shape);"); } }
The source code reveals that you can put a variable into a script engine's bindings, either by invoking ScriptEngine's put() method or by invoking Bindings's own put() method.
ScriptDemo4 creates the following output:
red rectangle blue triangle red rectangle