GraalVM Polyglot API for multi-language runtime environments with host-guest interoperability and security controls.
—
The GraalVM Polyglot API provides comprehensive capabilities for executing and parsing code across multiple programming languages. This includes source code creation, evaluation, parsing, and language bindings management.
The Source class represents source code with language and metadata information, supporting various input formats and caching strategies.
// Simple source creation
public static Source create(String language, CharSequence source);
// Builder pattern for advanced configuration
public static Source.Builder newBuilder(String language, CharSequence characters, String name);
public static Source.Builder newBuilder(String language, ByteSequence bytes, String name);
public static Source.Builder newBuilder(String language, File file);
public static Source.Builder newBuilder(String language, URL url);
public static Source.Builder newBuilder(String language, Reader source, String name);Basic Source Creation:
// Inline source code
Source jsSource = Source.create("js", "function factorial(n) { return n <= 1 ? 1 : n * factorial(n-1); }");
// From file
Source pySource = Source.newBuilder("python", new File("script.py")).build();
// From URL with caching
Source webSource = Source.newBuilder("js", new URL("https://example.com/script.js"))
.cached(true)
.build();public static final class Source.Builder {
// Content and encoding
public Source.Builder content(CharSequence characters);
public Source.Builder content(ByteSequence bytes);
public Source.Builder encoding(Charset encoding);
// Metadata
public Source.Builder name(String name);
public Source.Builder mimeType(String mimeType);
public Source.Builder uri(URI uri);
// Behavior configuration
public Source.Builder cached(boolean cached);
public Source.Builder interactive(boolean interactive);
public Source.Builder internal(boolean internal);
// Build the source
public Source build();
}// Language detection from file/URL
public static String findLanguage(File file);
public static String findLanguage(URL url);
public static String findLanguage(String mimeType);
// MIME type detection
public static String findMimeType(File file);
public static String findMimeType(URL url);Language Detection Example:
File jsFile = new File("script.js");
String language = Source.findLanguage(jsFile); // Returns "js"
String mimeType = Source.findMimeType(jsFile); // Returns "application/javascript"
// Create source with auto-detected language
Source source = Source.newBuilder(language, jsFile).build();public final class Source {
// Basic properties
public String getLanguage();
public String getName();
public String getPath();
public URL getURL();
public URI getURI();
public String getMimeType();
// Content access
public CharSequence getCharacters();
public CharSequence getCharacters(int lineNumber);
public ByteSequence getBytes();
public Reader getReader();
public InputStream getInputStream();
public int getLength();
// Source properties
public boolean isInteractive();
public boolean isInternal();
public boolean hasCharacters();
public boolean hasBytes();
// Line and column operations
public int getLineCount();
public int getLineNumber(int offset);
public int getColumnNumber(int offset);
}The Context class provides methods for evaluating source code with immediate execution and result retrieval.
// Evaluate source objects
public Value eval(Source source);
// Evaluate inline code
public Value eval(String languageId, CharSequence source);Evaluation Examples:
Context context = Context.create("js", "python");
// JavaScript evaluation
Value jsResult = context.eval("js", "Math.PI * 2");
System.out.println(jsResult.asDouble()); // 6.283185307179586
// Python evaluation
Value pyResult = context.eval("python", "[x**2 for x in range(5)]");
System.out.println(pyResult.toString()); // [0, 1, 4, 9, 16]
// Source object evaluation
Source factorial = Source.create("js", """
function factorial(n) {
return n <= 1 ? 1 : n * factorial(n-1);
}
factorial(5);
""");
Value factResult = context.eval(factorial);
System.out.println(factResult.asInt()); // 120Context context = Context.create("js", "python", "ruby");
// JavaScript sets up data
context.eval("js", "var shared = { message: 'Hello from JavaScript', count: 42 };");
// Python accesses and modifies
context.eval("python", """
import polyglot
shared = polyglot.eval(language="js", string="shared")
shared.message = "Modified by Python"
shared.count = shared.count * 2
""");
// Ruby reads the result
Value rubyResult = context.eval("ruby", """
shared = Polyglot.eval("js", "shared")
"#{shared[:message]} - Count: #{shared[:count]}"
""");
System.out.println(rubyResult.asString()); // "Modified by Python - Count: 84"Parsing allows you to compile source code without immediate execution, enabling syntax validation and AST preparation.
// Parse source objects
public Value parse(Source source);
// Parse inline code
public Value parse(String languageId, CharSequence source);Parsing Examples:
Context context = Context.create("js");
// Parse without execution
Source jsFunction = Source.create("js", "function greet(name) { return 'Hello, ' + name; }");
Value parsed = context.parse(jsFunction);
// The function is now compiled but not executed
// Execute later with different arguments
Value greeting1 = context.eval("js", "greet('Alice')");
Value greeting2 = context.eval("js", "greet('Bob')");Context context = Context.create("js");
// Parsing: Compiles but doesn't execute
Value parsed = context.parse("js", "console.log('This will not print during parsing')");
// No output - just compilation
// Evaluation: Compiles and executes
Value evaluated = context.eval("js", "console.log('This will print during evaluation')");
// Output: "This will print during evaluation"
// Execute the previously parsed code
context.eval("js", "console.log('Now executing parsed code')");
// Output: "This will not print during parsing"Bindings provide a way to share values between the host (Java) and guest languages, as well as between different guest languages.
// Get bindings for a specific language
public Value getBindings(String languageId);
// Get polyglot bindings (shared across languages)
public Value getPolyglotBindings();Language bindings behave like a Map-like object where you can store and retrieve values by name.
Context context = Context.create("js", "python");
// Get JavaScript bindings
Value jsBindings = context.getBindings("js");
// Add host objects to JavaScript
jsBindings.putMember("javaList", Arrays.asList(1, 2, 3, 4, 5));
jsBindings.putMember("javaMap", Map.of("key1", "value1", "key2", "value2"));
// JavaScript can now access these objects
context.eval("js", """
console.log('Java list length:', javaList.length);
console.log('Java map key1:', javaMap.get('key1'));
""");
// Set values from JavaScript
context.eval("js", "var jsResult = javaList.reduce((sum, x) => sum + x, 0);");
// Access JavaScript values from Java
Value jsResult = jsBindings.getMember("jsResult");
System.out.println("Sum calculated in JS: " + jsResult.asInt()); // 15Polyglot bindings are shared across all languages in a context:
Context context = Context.create("js", "python");
// Get shared polyglot bindings
Value polyglotBindings = context.getPolyglotBindings();
// Add shared data
polyglotBindings.putMember("sharedCounter", 0);
polyglotBindings.putMember("sharedConfig", Map.of("debug", true, "version", "1.0"));
// JavaScript increments counter
context.eval("js", """
Polyglot.import('sharedCounter');
var currentCount = Polyglot.import('sharedCounter');
Polyglot.export('sharedCounter', currentCount + 1);
""");
// Python also increments counter
context.eval("python", """
import polyglot
current = polyglot.import_value('sharedCounter')
polyglot.export_value('sharedCounter', current + 10)
""");
// Read final value
Value finalCount = polyglotBindings.getMember("sharedCounter");
System.out.println("Final counter: " + finalCount.asInt()); // 11The Context provides methods to convert Java objects to polyglot values that can be used by guest languages.
// Convert host objects to polyglot values
public Value asValue(Object hostValue);Conversion Examples:
Context context = Context.create("js");
// Convert various Java types
Value stringValue = context.asValue("Hello World");
Value intValue = context.asValue(42);
Value listValue = context.asValue(Arrays.asList(1, 2, 3));
Value mapValue = context.asValue(Map.of("name", "Alice", "age", 30));
// Custom objects (with HostAccess configuration)
public class Person {
@HostAccess.Export public String name;
@HostAccess.Export public int age;
@HostAccess.Export
public String greet() {
return "Hello, I'm " + name;
}
}
Context restrictedContext = Context.newBuilder("js")
.allowHostAccess(HostAccess.EXPLICIT)
.build();
Person person = new Person();
person.name = "Alice";
person.age = 30;
Value personValue = restrictedContext.asValue(person);
// Make available to JavaScript
Value jsBindings = restrictedContext.getBindings("js");
jsBindings.putMember("person", personValue);
restrictedContext.eval("js", """
console.log(person.name); // "Alice"
console.log(person.age); // 30
console.log(person.greet()); // "Hello, I'm Alice"
""");Contexts support lazy initialization of languages, improving startup performance when not all languages are immediately needed.
// Explicitly initialize a language
public boolean initialize(String languageId);Initialization Example:
Context context = Context.create("js", "python", "ruby");
// Initially, no languages are initialized
// First evaluation triggers initialization
long startTime = System.currentTimeMillis();
context.eval("js", "1 + 1"); // JavaScript gets initialized here
long jsInitTime = System.currentTimeMillis() - startTime;
// Subsequent evaluations are faster
startTime = System.currentTimeMillis();
context.eval("js", "2 + 2"); // No initialization needed
long jsExecTime = System.currentTimeMillis() - startTime;
// Pre-initialize Python for faster first execution
context.initialize("python");
Value pyResult = context.eval("python", "len([1, 2, 3, 4, 5])");Language execution can produce various types of errors that should be handled appropriately.
Context context = Context.create("js");
try {
// Syntax error
context.eval("js", "function malformed { missing parentheses }");
} catch (PolyglotException e) {
if (e.isSyntaxError()) {
System.out.println("Syntax error: " + e.getMessage());
SourceSection location = e.getSourceLocation();
if (location != null) {
System.out.printf("At line %d, column %d%n",
location.getStartLine(), location.getStartColumn());
}
}
}
try {
// Runtime error
context.eval("js", "nonExistentFunction()");
} catch (PolyglotException e) {
if (e.isGuestException()) {
System.out.println("Runtime error in guest language: " + e.getMessage());
Value guestObject = e.getGuestObject();
// Handle guest exception object
}
}Source sections provide detailed location information for debugging and error reporting.
public final class SourceSection {
public Source getSource();
public int getStartLine();
public int getEndLine();
public int getStartColumn();
public int getEndColumn();
public int getCharIndex();
public int getCharLength();
public int getCharEndIndex();
public boolean isAvailable();
public boolean hasLines();
public boolean hasColumns();
public boolean hasCharIndex();
public CharSequence getCharacters();
}Source Location Example:
Source source = Source.newBuilder("js", """
function calculate(x, y) {
return x / y; // Division by zero potential
}
calculate(10, 0);
""", "calculator.js").build();
Context context = Context.create("js");
try {
context.eval(source);
} catch (PolyglotException e) {
SourceSection location = e.getSourceLocation();
if (location != null) {
System.out.printf("Error in %s:%d:%d-%d:%d%n",
location.getSource().getName(),
location.getStartLine(), location.getStartColumn(),
location.getEndLine(), location.getEndColumn());
System.out.printf("Code: %s%n", location.getCharacters());
}
}// Enable source caching for repeated evaluation
Source cachedSource = Source.newBuilder("js", new File("frequent-script.js"))
.cached(true)
.build();
// Multiple contexts can share the cached source
Context context1 = Context.create("js");
Context context2 = Context.create("js");
context1.eval(cachedSource); // Parsed and cached
context2.eval(cachedSource); // Uses cached parse resultContext context = Context.create("js");
// For repeated execution, parse once and reference
Source template = Source.create("js", "function process(data) { /* complex logic */ }");
context.parse(template); // One-time compilation
// Then evaluate with different data
for (Object data : dataSet) {
Value bindings = context.getBindings("js");
bindings.putMember("currentData", data);
context.eval("js", "process(currentData)");
}Install with Tessl CLI
npx tessl i tessl/maven-org-graalvm-polyglot--graalvm-sdk