Skip to content

roastedroot/quickjs4j

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QuickJs4J

QuickJs4J lets you safely and easily run JavaScript from Java using a sandboxed environment.

Why Use QuickJs4J?

QuickJs4J provides a secure and efficient way to execute JavaScript within Java. By running code in a sandbox, it ensures:

  • Memory safety – JavaScript runs in isolation, protecting your application from crashes or memory leaks.
  • No system access by default – JavaScript cannot access the filesystem, network, or other sensitive resources unless explicitly allowed.
  • Portability – Being pure Java bytecode, it runs wherever the JVM does.
  • Native-image friendly – Compatible with GraalVM's native-image for fast, lightweight deployments.

Whether you're embedding scripting capabilities or isolating untrusted code, QuickJs4J is designed for safe and seamless integration.

Quick Start

Add QuickJs4J as a standard Maven dependency:

<dependency>
    <groupId>io.roastedroot</groupId>
    <artifactId>quickjs4j</artifactId>
</dependency>

Then run a simple "Hello World" example:

import io.roastedroot.quickjs4j.core.Runner;

try (var runner = Runner.builder().build()) {
    runner.compileAndExec("console.log(\"Hello QuickJs4J!\");");
    System.out.println(runner.stdout());
}

Note: You must explicitly print your JavaScript program’s output using System.out.

QuickJs4J runs JavaScript in a secure, sandboxed environment. To simplify communication, it allows you to bind Java methods so they can be called directly from JavaScript.

import io.roastedroot.quickjs4j.core.Engine;
import io.roastedroot.quickjs4j.core.Runner;
import io.roastedroot.quickjs4j.annotations.HostFunction;
import io.roastedroot.quickjs4j.annotations.Builtins;

@Builtins("from_java")
class JavaApi {
    @HostFunction("my_java_func")
    public String add(int x, int y) {
        return "hello " + (x + y);
    }

    @HostFunction("my_java_check")
    public void check(String value) {
        assert("hello 42".equals(value));
    }
}

var engine =
    Engine.builder()
          .addBuiltins(JavaApi_Builtins.toBuiltins(new JavaApi()))
          .build();

try (var runner = Runner.builder().withEngine(engine).build()) {
    runner.exec("from_java.my_java_check(from_java.my_java_func(40, 2));");
}

Calling JavaScript from Java

To invoke functions defined in a JavaScript or TypeScript library, define an interface like this:

import io.roastedroot.quickjs4j.core.Engine;
import io.roastedroot.quickjs4j.core.Runner;
import io.roastedroot.quickjs4j.annotations.GuestFunction;
import io.roastedroot.quickjs4j.annotations.Invokables;

@Invokables("from_js")
interface JsApi {
    @GuestFunction
    String sub(int x, int y);
}

var engine =
    Engine.builder()
          .addInvokables(JsApi_Invokables.toInvokables())
          .build();

// Inlined for demo; normally loaded from a packaged distribution file
String jsLibrary = "function sub(x, y) { return \"hello js \" + (x - y); };";

try (var runner = Runner.builder().withEngine(engine).build()) {
    var jsApi = JsApi_Invokables.create(jsLibrary, runner);
    System.out.println(jsApi.sub(3, 1));
}

Enabling Annotation Processing

Configure the annotation processor in your Maven pom.xml:

<dependencies>
  <dependency>
    <groupId>io.roastedroot</groupId>
    <artifactId>quickjs4j-annotations</artifactId>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
        <annotationProcessorPaths>
          <path>
            <groupId>io.roastedroot</groupId>
            <artifactId>quickjs4j-processor</artifactId>
          </path>
        </annotationProcessorPaths>
      </configuration>
    </plugin>
  </plugins>
</build>

Passing Java Object References

Sometimes, you may want to pass a Java object reference to JavaScript without serializing it (i.e., keeping it only in Java memory). Use HostRefs as shown below:

import io.roastedroot.quickjs4j.annotations.HostRefParam;
import io.roastedroot.quickjs4j.annotations.ReturnsHostRef;

@ReturnsHostRef
@HostFunction("my_java_ref")
public String myRef() {
    return "a Java string not visible in JS";
}

@HostFunction("my_java_ref_check")
public void myRefCheck(@HostRefParam String value) {
    ...
}

try (var myTestModule = new MyJsTestModule()) {
    myTestModule.exec("my_java_ref_check(my_java_ref());");
}

High Level API

An higher level API is exposed for convenience to wrap everything up for the most common use cases. You can use the ScriptInterface annotation:

import io.roastedroot.quickjs4j.annotations.ScriptInterface;

public class CalculatorContext {
    public void log(String message) {
        System.out.println("LOG>> " + message);
    }
}

@ScriptInterface(context = CalculatorContext.class)
public interface Calculator {
    int add(int term1, int term2);

    int subtract(int term1, int term2);
}

try (var calculator = new Calculator_Proxy(jsLibrary, new CalculatorContext()) {
    calculator.add(1, 2);
    calculator.subtract(3, 1);
}

NOTE: currently only basic use is supported.

Building a JS/TS Library

To build your JavaScript/TypeScript library, refer to this example.

Key points:

  • Output an ECMAScript module using tools like esbuild:

    esbuild your_file.js --format=esm
  • The library must export the expected functions.

  • The annotation processor will generate a .mjs file at:

    target/classes/META-INF/quickjs4j/builtin_name.mjs
    

    This file bridges your Java and JS code.

Building the Project

To build this project, you'll need:

  • A Rust toolchain
  • JDK 11 or newer
  • Maven

Steps:

rustup target add wasm32-wasip1  # Only needed once

cd javy-plugin
make build
cd ..

mvn clean install

Acknowledgements

This project stands on the shoulders of giants:

  • QuickJS – a small, embeddable JavaScript engine
  • Javy – a toolchain for compiling JavaScript to WebAssembly
  • Chicory – a native JVM WebAssembly runtime

About

Run JavaScript from Java in a safe sandbox.

Resources

License

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •  

Languages