GraalJS ScriptEngine implementation based on JSR-223 providing JavaScript execution capabilities through the javax.script.ScriptEngine API.
—
Advanced configuration capabilities for GraalJS ScriptEngine including security settings, performance options, and polyglot context management. Provides multiple configuration approaches from simple binding-based options to full polyglot context builders.
Static factory methods for creating GraalJSScriptEngine instances with various levels of customization.
/**
* Creates a new GraalJSScriptEngine with default configuration
* Default includes syntax extensions, load/print/arguments support enabled
* @return New GraalJSScriptEngine with standard settings
*/
static GraalJSScriptEngine create();
/**
* Creates a new GraalJSScriptEngine with custom polyglot engine and context configuration
* @param engine Polyglot engine to use (null for default)
* @param newContextConfig Base configuration for new contexts (null for default)
* @return New GraalJSScriptEngine with custom configuration
*/
static GraalJSScriptEngine create(Engine engine, Context.Builder newContextConfig);Usage Examples:
// Simple default creation
GraalJSScriptEngine defaultEngine = GraalJSScriptEngine.create();
defaultEngine.eval("console.log('Hello, World!');");
// Custom engine with specific options
Engine customEngine = Engine.newBuilder()
.allowExperimentalOptions(true)
.option("engine.MaxCompilationDelay", "5000")
.build();
Context.Builder contextConfig = Context.newBuilder("js")
.allowHostAccess(HostAccess.ALL)
.allowIO(IOAccess.ALL)
.option("js.ecmascript-version", "2022");
GraalJSScriptEngine customEngine = GraalJSScriptEngine.create(customEngine, contextConfig);
// Custom configuration without custom engine
GraalJSScriptEngine configuredEngine = GraalJSScriptEngine.create(null, contextConfig);Direct access to underlying GraalVM polyglot contexts for advanced operations and fine-grained control.
/**
* Returns the polyglot context associated with the default ScriptContext
* @return GraalVM polyglot Context instance
*/
Context getPolyglotContext();
/**
* Returns the polyglot context associated with a specific ScriptContext
* If context not initialized, creates it using default context builder
* @param scriptContext The ScriptContext to get polyglot context for
* @return GraalVM polyglot Context instance for the ScriptContext
*/
Context getPolyglotContext(ScriptContext scriptContext);
/**
* Returns the polyglot engine associated with this script engine
* @return GraalVM polyglot Engine instance
*/
Engine getPolyglotEngine();Usage Examples:
GraalJSScriptEngine engine = GraalJSScriptEngine.create();
// Access default polyglot context
Context defaultContext = engine.getPolyglotContext();
Value jsBindings = defaultContext.getBindings("js");
jsBindings.putMember("javaObject", new Object());
// Work with multiple script contexts
SimpleScriptContext context1 = new SimpleScriptContext();
SimpleScriptContext context2 = new SimpleScriptContext();
Context polyContext1 = engine.getPolyglotContext(context1);
Context polyContext2 = engine.getPolyglotContext(context2);
// Each ScriptContext has its own polyglot context
assert polyContext1 != polyContext2;
assert polyContext1.getEngine() == polyContext2.getEngine();
// Direct polyglot operations
polyContext1.eval("js", "var ctx1Variable = 'context1'");
polyContext2.eval("js", "var ctx2Variable = 'context2'");
// Access polyglot engine
Engine polyEngine = engine.getPolyglotEngine();
System.out.println("Engine version: " + polyEngine.getVersion());Configure GraalJS context options through special binding keys that are processed during context initialization.
// Magic binding option prefix constant
static final String MAGIC_OPTION_PREFIX = "polyglot.js.";
// Magic binding option keys (set via Bindings.put() before context initialization)
"polyglot.js.allowHostAccess" // Boolean - Enable/disable host object access
"polyglot.js.allowNativeAccess" // Boolean - Enable/disable native library access
"polyglot.js.allowCreateThread" // Boolean - Enable/disable thread creation
"polyglot.js.allowIO" // Boolean - Enable/disable I/O operations
"polyglot.js.allowHostClassLookup" // Boolean or Predicate<String> - Control class lookup
"polyglot.js.allowHostClassLoading" // Boolean - Enable/disable class loading
"polyglot.js.allowAllAccess" // Boolean - Enable/disable all access permissions
"polyglot.js.nashorn-compat" // Boolean - Enable/disable Nashorn compatibility mode
"polyglot.js.ecmascript-version" // String - Set ECMAScript version
"polyglot.js.intl-402" // Boolean - Enable/disable Intl API supportUsage Examples:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
// Configure security options BEFORE first evaluation
bindings.put("polyglot.js.allowHostAccess", true);
bindings.put("polyglot.js.allowHostClassLookup", (Predicate<String>) s -> s.startsWith("java."));
bindings.put("polyglot.js.allowIO", false); // Disable I/O for security
// Configure language options
bindings.put("polyglot.js.ecmascript-version", "2022");
bindings.put("polyglot.js.nashorn-compat", false);
// Set Java objects accessible to JavaScript
bindings.put("javaList", Arrays.asList(1, 2, 3));
bindings.put("javaMap", Map.of("key", "value"));
// Now evaluate - context will be initialized with configured options
engine.eval("console.log(javaList.length);"); // Works due to allowHostAccess
engine.eval("console.log(Java.type('java.lang.String'));"); // Works due to allowHostClassLookup
// Attempting to set magic options after context initialization fails
try {
engine.eval("var dummy = true;"); // Forces context initialization
bindings.put("polyglot.js.allowIO", true); // This will throw IllegalStateException
} catch (IllegalStateException e) {
System.out.println("Cannot set options after context initialization");
}Configure GraalJS options globally through JVM system properties.
System Property Format:
# Engine options (affect all ScriptEngine instances)
-Dpolyglot.js.ecmascript-version=2022
-Dpolyglot.js.intl-402=true
# Global compatibility mode
-Dpolyglot.js.nashorn-compat=true
# Insecure access mode (development only)
-Dgraaljs.insecure-scriptengine-access=trueUsage Examples:
// Set system properties programmatically (before creating engines)
System.setProperty("polyglot.js.ecmascript-version", "2022");
System.setProperty("polyglot.js.intl-402", "true");
// Create engines - they inherit system property settings
ScriptEngine engine1 = new ScriptEngineManager().getEngineByName("js");
ScriptEngine engine2 = new ScriptEngineManager().getEngineByName("js");
// Both engines use ES2022 with Intl support
engine1.eval("console.log(Object.hasOwn({}, 'prop'));"); // ES2022 feature
engine2.eval("console.log(new Intl.DateTimeFormat('en-US'));"); // Intl API
// Command line usage:
// java -Dpolyglot.js.ecmascript-version=2022 -Dpolyglot.js.nashorn-compat=true MyAppFull control over polyglot context configuration through direct Context.Builder usage.
/**
* Example Context.Builder configuration options
*/
Context.Builder contextBuilder = Context.newBuilder("js")
// Security settings
.allowHostAccess(HostAccess.ALL) // Or HostAccess.NONE, custom HostAccess
.allowHostClassLookup(s -> true) // Or specific predicate
.allowHostClassLoading(true)
.allowNativeAccess(true)
.allowCreateThread(true)
.allowIO(IOAccess.ALL) // Or IOAccess.NONE
.allowAllAccess(true) // Enables all permissions
// Language options
.option("js.ecmascript-version", "2022")
.option("js.intl-402", "true")
.option("js.nashorn-compat", "true")
.option("js.syntax-extensions", "true")
// I/O configuration
.in(System.in)
.out(System.out)
.err(System.err)
// Engine configuration
.allowExperimentalOptions(true);Usage Examples:
// Secure configuration for untrusted code
Context.Builder secureConfig = Context.newBuilder("js")
.allowHostAccess(HostAccess.NONE)
.allowHostClassLookup(s -> false)
.allowHostClassLoading(false)
.allowNativeAccess(false)
.allowCreateThread(false)
.allowIO(IOAccess.NONE)
.option("js.ecmascript-version", "2022");
GraalJSScriptEngine secureEngine = GraalJSScriptEngine.create(null, secureConfig);
// Permissive configuration for trusted code
Context.Builder permissiveConfig = Context.newBuilder("js")
.allowAllAccess(true)
.allowHostClassLookup(s -> true)
.option("js.nashorn-compat", "true")
.option("js.ecmascript-version", "2022");
GraalJSScriptEngine permissiveEngine = GraalJSScriptEngine.create(null, permissiveConfig);
// Development configuration with custom I/O
StringWriter output = new StringWriter();
StringWriter errors = new StringWriter();
Context.Builder devConfig = Context.newBuilder("js")
.allowAllAccess(true)
.out(new WriterOutputStream(output, StandardCharsets.UTF_8))
.err(new WriterOutputStream(errors, StandardCharsets.UTF_8))
.option("js.syntax-extensions", "true");
GraalJSScriptEngine devEngine = GraalJSScriptEngine.create(null, devConfig);
devEngine.eval("console.log('Hello'); console.error('Warning');");
System.out.println("Output: " + output.toString());
System.out.println("Errors: " + errors.toString());Special compatibility mode for applications migrating from Oracle Nashorn ScriptEngine.
// Enable via system property
System.setProperty("polyglot.js.nashorn-compat", "true");
// Enable via magic binding
bindings.put("polyglot.js.nashorn-compat", true);
// Enable via context builder
Context.Builder nashornConfig = Context.newBuilder("js")
.option("js.nashorn-compat", "true");Nashorn Compatibility Features:
Usage Examples:
// Global Nashorn compatibility
System.setProperty("polyglot.js.nashorn-compat", "true");
ScriptEngine nashornCompatEngine = new ScriptEngineManager().getEngineByName("js");
// Nashorn-style operations work automatically
nashornCompatEngine.put("javaObject", new Object());
nashornCompatEngine.eval("print(javaObject.getClass().getName());");
// Per-engine Nashorn compatibility
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.put("polyglot.js.nashorn-compat", true);
bindings.put("polyglot.js.allowAllAccess", true);
engine.eval("var ArrayList = Java.type('java.util.ArrayList');");
engine.eval("var list = new ArrayList(); list.add('item');");Proper lifecycle management of engines, contexts, and associated resources.
/**
* Closes the current context and makes it unusable
* Operations performed after closing will throw IllegalStateException
*/
void close();
/**
* Check if context is closed
*/
boolean isClosed(); // Available on polyglot ContextUsage Examples:
// Automatic resource management
try (GraalJSScriptEngine engine = GraalJSScriptEngine.create()) {
engine.eval("console.log('Working...');");
// Engine automatically closed when leaving try block
}
// Manual resource management
GraalJSScriptEngine engine = GraalJSScriptEngine.create();
try {
engine.eval("var result = computeExpensiveOperation();");
Object result = engine.get("result");
return result;
} finally {
engine.close(); // Ensure cleanup
}
// Managing polyglot contexts directly
Context polyglotContext = engine.getPolyglotContext();
try {
polyglotContext.eval("js", "performWork()");
} finally {
if (!polyglotContext.isClosed()) {
polyglotContext.close();
}
}
// Resource sharing with custom engine
Engine sharedEngine = Engine.newBuilder().build();
try {
GraalJSScriptEngine engine1 = GraalJSScriptEngine.create(sharedEngine, null);
GraalJSScriptEngine engine2 = GraalJSScriptEngine.create(sharedEngine, null);
// Use both engines - they share the polyglot engine
engine1.eval("var shared = 'data';");
engine2.eval("var other = 'data';");
// Close individual engines
engine1.close();
engine2.close();
} finally {
// Close shared engine when all ScriptEngines are done
sharedEngine.close();
}Install with Tessl CLI
npx tessl i tessl/maven-org-graalvm-js--js-scriptengine