Spring boot integrated GraalVM JS engine quick start demo

HBLOG
2 min readMar 8, 2024

--

一、GraalVM.js introduction

Is a JavaScript interpreter/compiler capable of running Node.js applications on the JVM;

Main application scenarios

Dynamically change program execution logic through JS, such as: risk control rules, service orchestration, etc.

二、Code Project

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-demo</artifactId>
<groupId>com.et</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>graalvm-js</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
<version>20.2.0</version>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js</artifactId>
<version>20.2.0</version>
</dependency>
</dependencies>
</project>

Application.yaml

server:
port: 8088

Main class

package com.et.graalvm.js;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

Code repository

三、Test

local invoke

package com.et.graalvm.js;
import org.junit.Test;
import javax.script.*;
/**
* @author liuhaihua
* @version 1.0
* @ClassName com.et.graalvm.js.JSTest
* @Description todo
* @date 2024/03/07 9:47
*/
public class JSTest {
@Test
public void test10(){
// create JavaScript engine
ScriptEngine jsEngine = new ScriptEngineManager().getEngineByName("js");
// ScriptEngine jsEngine = new ScriptEngineManager().getEngineByExtension("js");
// ScriptEngine jsEngine = new ScriptEngineManager().getEngineByMimeType("text/javascript");
// method 1,set variables
jsEngine.put("hello", "jack");
// method 2,use binding to set variables
SimpleBindings bindings = new SimpleBindings();
bindings.put("hello","world");
jsEngine.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
// method 3,use Context to set variables
ScriptContext scriptContext = jsEngine.getContext();
scriptContext.setAttribute("hello", "polo", ScriptContext.ENGINE_SCOPE);
try {
// method 1,directly call
jsEngine.eval("print(hello)");
// method 2,Compile and call (needs to be called repeatedly, it is recommended to compile first and then call)
if (jsEngine instanceof Compilable){
CompiledScript compileScript = ((Compilable) jsEngine).compile("print(hello)");
if (compileScript != null){
for (int i = 0; i < 10; i++) {
compileScript.eval();
}
}
}
Invocable invocable = ((Invocable)jsEngine);
// Method 3, use top-level methods in JavaScript
jsEngine.eval("function greet(name) { print('Hello, ' + name); } ");
invocable.invokeFunction("greet", "tom");
// Method 4, using a method of an object
jsEngine.eval("var obj = { getGreeting: function(name){ return 'hello, ' + name; } } ");
Object obj = jsEngine.get("obj");
Object result = invocable.invokeMethod(obj, "getGreeting", "kitty");
System.out.println(result);
} catch (ScriptException | NoSuchMethodException e) {
e.printStackTrace();
}
}
}

remote invoke

package com.et.graalvm.js;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class RemoteJSTest {
public static void main(String[] args) throws IOException, ScriptException {
URL jsUrl = new URL("https://example.com/script.js");
URLConnection connection = jsUrl.openConnection();
InputStream inputStream = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
reader.close();
inputStream.close();
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("nashorn");
String script = sb.toString();
engine.eval(script);
Object result = engine.eval("hello()");
System.out.println(result);
}
}

四、reference

--

--