GraalJS

GraalJSは、GraalVM上に構築された高速なJavaScript言語実装です。ECMAScriptに準拠しており、Javaやその他のGraal言語との相互運用性、一般的なツール、そしてGraalVM JDK上で実行される場合は、デフォルトでGraal JITコンパイラによる最高の性能を提供します。Oracle JDKまたはOpenJDKでもGraalJSを使用できます。

GraalJSは、新しいECMAScript標準と機能をサポートするJavaScriptエンジンにNashornまたはRhinoから移行したいプロジェクトに適した代替手段です。以下に示すように、GraalJSをJavaアプリケーションに簡単に追加できます。

JVMでのGraalJS入門 #

JavaホストアプリケーションにJavaScriptを埋め込むには、プロジェクトの依存関係としてGraalJSを追加することで有効にします。必要なアーティファクトはすべてMaven Centralから直接ダウンロードできます。埋め込みに関わるすべてのアーティファクトは、Maven依存関係グループorg.graalvm.polyglotにあります。

以下は、JavaScript埋め込みのMaven構成です。

<dependency>
    <groupId>org.graalvm.polyglot</groupId>
    <artifactId>polyglot</artifactId>
    <version>${graaljs.version}</version>
</dependency>
<dependency>
    <groupId>org.graalvm.polyglot</groupId>
    <artifactId>js</artifactId>
    <version>${graaljs.version}</version>
    <type>pom</type>
</dependency>

これは、Oracle GraalVM上に構築され、GraalVM Free Terms and Conditions (GFTC) のもとでライセンス供与されているGraalJSを有効にします。GraalVM Community Edition上に構築されたGraalJSを使用する場合は、jsの代わりにartifactId js-communityを使用してください。

Mavenプロジェクトを作成し、JavaにJavaScriptを埋め込んで実行する手順を順を追って説明します。このサンプルアプリケーションは、GraalVM for JDK 23とGraalVM Polyglot APIバージョン24.1.0でテストされています。ダウンロードページでGraalVMのインストール方法を確認してください。

  1. お好みのIDEまたはターミナルから、「helloworld」という名前の新しいMaven Javaプロジェクトを作成し、以下の構造にします。
     ├── pom.xml
     └── src
         ├── main
         │   └── java
         │       └── com
         │           └── example
         │               └── App.java
    

    たとえば、クイックスタートアーキタイプを使用して新しいMavenプロジェクトを作成するには、次のコマンドを実行できます。

     mvn archetype:generate -DgroupId=com.example -DartifactId=helloworld -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false
    
  2. App.javaの内容を次のコードに置き換えます。
     package com.example;
    
     import org.graalvm.polyglot.*;
     import org.graalvm.polyglot.proxy.*;
    
     public class App {
    
         static String JS_CODE = "(function myFun(param){console.log('Hello ' + param + ' from JS');})";
    
         public static void main(String[] args) {
             String who = args.length == 0 ? "World" : args[0];
             System.out.println("Hello " + who + " from Java");
             try (Context context = Context.create()) {
                 Value value = context.eval("js", JS_CODE);
                 value.execute(who);
             }
         }
     }
    

    このサンプルアプリケーションはPolyglot API を使用し、JavaScript関数をJava値として返します。

  3. JavaScriptエンジン(GraalJS)を含めるには、pom.xmlに次の依存関係を追加します。
     <dependencies>
         <dependency>
             <groupId>org.graalvm.polyglot</groupId>
             <artifactId>polyglot</artifactId>
             <version>${graaljs.version}</version>
         </dependency>
         <dependency>
             <groupId>org.graalvm.polyglot</groupId>
             <artifactId>js</artifactId>
             <version>${graaljs.version}</version>
             <type>pom</type>
         </dependency>
     </dependencies>
    

    <properties>セクションにgraaljs.versionプロパティを追加して、GraalJSとGraalVM Polyglot APIのバージョンを設定します。または、${graaljs.version}をバージョン文字列に直接置き換えることもできます。この例では24.1.0を使用します。

     <properties>
         <graaljs.version>24.1.0</graaljs.version>
     </properties>
    
  4. プロジェクトをJARファイルにコンパイルし、すべてのランタイム依存関係をディレクトリにコピーするためのMavenプラグインをpom.xmlファイルに追加します。
     <build>
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>3.13.0</version>
                 <configuration>
                     <fork>true</fork>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
                 <version>3.4.2</version>
                 <configuration>
                     <archive>
                         <manifest>
                             <mainClass>com.example.App</mainClass>
                         </manifest>
                     </archive>
                 </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-dependency-plugin</artifactId>
                 <version>3.8.0</version>
                 <executions>
                     <execution>
                         <id>copy-dependencies</id>
                         <phase>package</phase>
                         <goals>
                             <goal>copy-dependencies</goal>
                         </goals>
                         <configuration>
                             <outputDirectory>${project.build.directory}/modules</outputDirectory>
                             <includeScope>runtime</includeScope>
                             <includeTypes>jar</includeTypes>
                         </configuration>
                     </execution>
                 </executions>
             </plugin>
         </plugins>
     </build>
    
  5. (オプション)アプリケーションにmodule-info.javaを追加します。モジュールパスでアプリケーションを実行する場合は、src/main/javaに次の内容のmodule-info.javaファイルを作成します。
     module com.example {
         requires org.graalvm.polyglot;
     }
    
  6. プロジェクトをコンパイルしてパッケージ化します。
     mvn clean package
    
  7. GraalVMまたはその他の互換性のあるJDKを使用してアプリケーションを実行します。ステップ5でmodule-info.javaを含めた場合は、次のコマンドのいずれかを使用して、モジュールパスでアプリケーションを実行できます。
    java --module-path target/modules:target/helloworld-1.0-SNAPSHOT.jar --module com.example/com.example.App "GraalVM"
    java -p target/modules:target/helloworld-1.0-SNAPSHOT.jar -m com.example/com.example.App "GraalVM"
    

    それ以外の場合は、モジュールパスに依存関係、クラスパスにアプリケーションを使用して実行できます。

    java --module-path target/modules --add-modules=org.graalvm.polyglot -cp target/helloworld-1.0-SNAPSHOT.jar com.example.App "GraalVM"
    java --module-path target/modules --add-modules=org.graalvm.polyglot -jar target/helloworld-1.0-SNAPSHOT.jar "GraalVM"
    

    または、すべてをクラスパスでも実行できます(この場合は*を使用するか、すべてのJARファイルを指定する必要があります)。

    java -cp "target/modules/*:target/helloworld-1.0-SNAPSHOT.jar" com.example.App "GraalVM"
    # or using shell expansion:
    java -cp "$(find target/modules -name '*.jar' | tr '\n' :)target/helloworld-1.0-SNAPSHOT.jar" com.example.App "GraalVM"
    java -cp "$(printf %s: target/modules/*.jar)target/helloworld-1.0-SNAPSHOT.jar" com.example.App "GraalVM"
    

    注:すべての依存関係を1つの「fat」JARにバンドルすること(たとえば、Maven Assemblyプラグインを使用すること)は、問題を引き起こし、GraalVM Native Imageによる事前コンパイルを妨げる可能性があるため、お勧めしません。代わりに、すべてのorg.graalvm.*依存関係について、元の個別のJARファイルを使用し、できればモジュールパスを使用することをお勧めします。言語埋め込みガイドで詳細を確認してください。

ソースコードユニットは、例に示すようにString、ファイル、URLから読み込んだもの、およびその他の手段で表現できます。関数定義(())をラップすることで、関数をすぐに返します。

Value f = context.eval("js", "(function f(x, y) { return x + y; })");
Value result = f.execute(19, 23);

以下に示すように、JavaScriptからJava型をルックアップしてインスタンス化することもできます。

try (Context context = Context.newBuilder()
                           .allowHostAccess(HostAccess.newBuilder(HostAccess.ALL).build())
                           .allowHostClassLookup(className -> true)
                       .build()) {
    java.math.BigDecimal v = context.eval("js",
            "var BigDecimal = Java.type('java.math.BigDecimal');" +
            "BigDecimal.valueOf(10).pow(20)")
        .asHostObject();
    assert v.toString().equals("100000000000000000000");
}

Polyglot APIには、JavaScriptオブジェクト、数値、文字列、配列に直接アクセスするなど、Javaからゲスト言語コードにアクセスする多くの方法があります。JavaScriptとJavaの相互運用性について詳しく知りたい場合、およびその他の例については、Java相互運用性ガイドを参照してください。

GraalJSは、GitHubからダウンロードできるスタンドアロン配布物としても利用できます。こちらで詳細をご覧ください。

GraalJSユーザー向けに、次のドキュメントを提供しています。

移行ガイド

レガシー環境からの移行について詳しく知る

お問い合わせ