Java で JavaScript を実行するもう一つの方法


はじめに

Java 上で JavaScript を実行するスクリプトエンジンは以下のように変遷してきました。

現在は、スクリプトエンジンとして GraalJS を使うのが選択肢になると思います。

以下のような依存を追加し、

implementation("org.graalvm.polyglot:polyglot:24.0.0")
implementation("org.graalvm.polyglot:js:24.0.0")

Nashorn などと同じように以下のようにスクリプトエンジンを取得して使うことができます。

var engine = new ScriptEngineManager().getEngineByName("graal.js");


javet

Java 組み込みのスクリプトエンジンによるアプローチではなく、Java Native Interface (JNI) により直接V8を操作するライブラリが javet です。Java + V8 (JAVa + V + EighT)。

リポジトリは以下となります。

github.com

GraalJS と比較してパフォーマンスで優位なようです。

ここでは、javet の導入を簡単に紹介します。


javet の導入

Gradle でプロジェクトを作成します。

$ mkdir javet-example
$ cd javet-example
$ gradle init --type java-application --dsl kotlin --test-framework junit-jupiter --project-name javet-example --package javet.example

javet は JNI 経由で V8 を使うため、ライブラリはプラットフォーム毎に提供されています。

そのため、build.gradle.kts には com.caoccao.javet の依存をプラットフォームに応じて追加します。

import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform

plugins {
    application
}

repositories {
    mavenCentral()
}

val os   = DefaultNativePlatform.getCurrentOperatingSystem()
val arch = DefaultNativePlatform.getCurrentArchitecture()
val artifact = when {
    os.isMacOsX  && arch.isArm64 -> "javet-macos"
    os.isMacOsX  && arch.isAmd64 -> "javet-macos"
    os.isLinux   && arch.isArm64 -> "javet-linux-arm64"
    os.isLinux   && arch.isAmd64 -> "javet"
    os.isWindows && arch.isAmd64 -> "javet"
    else -> throw Error("Unsupported OS: $os, ARCH: $arch")
}

dependencies {
    implementation("com.caoccao.javet:${artifact}:3.1.0")
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(21))
    }
}

application {
    mainClass.set("javet.example.App")
}


V8Runtime の利用

利用は、V8Host.getNodeInstance() からランタイムを取得して実行するだけです。

以下のようになります。

package javet.example;  
  
import com.caoccao.javet.interop.V8Host;  
import com.caoccao.javet.interop.V8Runtime;  
  
public class App {  
  
    public static void main(String[] args) throws Exception {  
        try (V8Runtime v8Runtime = V8Host.getNodeInstance().createV8Runtime()) {  
            int ret = v8Runtime.getExecutor("1 + 2").executeInteger();  
            System.out.println("1 + 2 = " + ret);  
        }  
    }  
  
}

実行すれば、以下のような結果が得られます。

./gradlew run

1 + 2 = 3

その他詳細は以下のドキュメントを参照くてください。

www.caoccao.com