GraalVM Polyglot Programming with Java, JavaScript, Ruby, and Python
GraalVM is a powerful runtime that enables you to run code written in multiple languages—like JavaScript, Python, and Ruby—side by side within the same Java application. This blog shows how to perform polyglot programming using GraalVM and Java.
✨ Prerequisites
- Java 17+ (GraalVM-based JDK recommended)
- Maven
- Proper GraalVM language libraries added as dependencies
🚀 Maven Dependencies
Add the following dependencies to your pom.xml
:
<dependencies>
<!-- JavaScript support -->
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>js-community</artifactId>
<version>24.2.1</version>
<type>pom</type>
</dependency>
<!-- Python support -->
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>python</artifactId>
<version>24.2.0</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.graalvm.python</groupId>
<artifactId>python-embedding</artifactId>
<version>24.2.0</version>
</dependency>
<!-- Ruby support -->
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>ruby</artifactId>
<version>24.2.0</version>
<type>pom</type>
</dependency>
</dependencies>
🔧 Java Polyglot Demo
package ai;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.io.IOAccess;
public class PolyglotDemo {
public static void main(String[] args) {
// Ruby execution
try (Context context = Context.create()) {
context.eval("ruby", "require 'json';");
String rubyScript = "puts 'Hello from Ruby!'";
context.eval(Source.create("ruby", rubyScript));
String rubyJson = context.eval("ruby",
"JSON.generate({ message: 'Hello from Ruby' })").toString();
System.out.println("Ruby JSON: " + rubyJson);
}
// JavaScript execution
try (Context context = Context.create()) {
Value result = context.eval("js", "21 + 21");
System.out.println("Result from JavaScript: " + result.asInt());
}
// Python execution with restricted I/O
try (Context context = Context.newBuilder("python")
.allowIO(IOAccess.newBuilder()
.allowHostFileAccess(false)
.allowHostSocketAccess(false)
.build())
.allowCreateThread(false)
.allowNativeAccess(false)
.build()) {
context.eval("python", "print('Hello from GraalPy!')");
}
}
}
💡 Key Concepts
Context.create(...)
: Bootstraps a new language runtime.eval("lang", "code")
: Executes code in that language- Polyglot contexts can be reused or isolated
- Security: Fine-grained I/O, native access, and thread access control
📊 Use Cases
- Embedding business rules in JS/Python
- Running ML models in Python from Java
- Integrating Ruby DSLs into Java platforms
⚠️ Gotchas
- You must use the right artifacts (e.g.,
python-embedding
) for non-Java languages - Not all standard library features work out-of-the-box (especially with I/O disabled)
- Language runtimes must be on classpath/module-path