JDK 14でNashornが削除される

前回は、Javaに標準ライブラリとして搭載されているJava Scripting APIと、JDKに付属するJavaScriptエンジンである「Nashorn」を使って、JavaとJavaScriptを相互に連携させる方法について紹介した。NanhornはJava 8の頃からJDKに標準で付属していたが、2018年9月にリリースされたJDK 11で非推奨扱い(Deprecated)となった。

Nashornの非推奨化は「JEP 335: Deprecate the Nashorn JavaScript Engine」として提案された。非推奨化の理由としては、Nashornの実装が最新のJavaScript仕様をサポートできていない点がある。NashornがサポートしているJavaScript仕様は2015年にリリースされたECMAScript 6であり、最新のECMAScript 2020やECMAScript 2019などとは機能的に大きな差がある。とはいえ、Nashornの体制ではもう現在のJavaScriptの進化を追ってはいけないという判断だ。

JDK 11の時点では非推奨になっただけで、Nashornはまだ使えなくなったわけではないが、その後「JEP 372: Remove the Nashorn JavaScript Engine」が提案されて、2020年9月リリース予定のJDK 15で正式に削除されることになった。

  • NashornはJDK 11で非推奨になり、JDK 15で削除される

    NashornはJDK 11で非推奨になり、JDK 15で削除される

これらのJEPの特筆すべきポイントは以下の通りだ。

  • Java Scripting APIには影響しない(あくまでもNashornが削除されるだけ)
  • jdk.scripting.nashornモジュールが削除される
  • jdk.scripting.nashorn.shellが削除される

jdk.scripting.nashornモジュールには、Java Scripting APIのNashorn用の実装が含まれている。また、jdk.scripting.nashorn.shellモジュールには、コマンドラインツールの「jjs」が含まれる。

JDKから削除されたあとも、Nashorn自体を自前でセットアップして使うことはできる。とはいえ、今後のメンテナンスのことも考えれば、より新しい別のJavaScriptエンジンに移行する方が現実的と言える。

GraalJS(GraalVM JavaScript)とは

そこで、Nashornからの移行先としてもっとも有力な候補となっているのが「GraalVM JavaScript」、通称「GraalJS」だ。GraalVMはJavaで実装された汎用仮想マシンで、Oracleによって開発されている。JDKおよびJavaVMを備えており、事前コンパイルやJITコンパイルなどの技術によってJavaアプリケーションを高速に実行することができる。

GraalVMのもう1つの側面が多言語対応のランタイムという姿で、Javaだけでなく、JavaScriptをはじめとするさまざまな言語の実行環境として利用可能になっている。GraalVMにはTruffleと呼ばれるプログラミング言語を開発するためのフレームワークが備わっており、これを使うことでGraalVM上で実行可能な任意の言語用のインタプリタを比較的容易に実装することができるわけだ。

この機能によって、GraalVMはJavaScriptの実行もサポートしており、デフォルトでJavaScriptエンジンが含まれている。このJavaScriptエンジンはGraalJSとも呼ばれており、本稿執筆時点ではECMAScript 2019に準拠している。

GraalJSはNashornと同様にJava Scripting APIを使ったJavaプログラムからの利用が可能なほか、jjsツールに相当するコマンドラインツールの「js」も用意されている。Nashornとの互換性も考慮して作られているため、移行先としては最適と言えるだろう。

  • GraalVMの概念図 - https://www.graalvm.org/docs/ より

    GraalVMの概念図 - https://www.graalvm.org/docs/ より

GraalJS(GraalVM)のインストール

GraalJSはGraalVMに標準で付属している。GraalVMは下記のサイトからWindows版、Linux版、macOS版のそれぞれがダウンロードできる。Comunity Edition(CE)とEnterprise Edition(EE)があり、CEの方は無料で利用可能となっている。本稿執筆時点では、バージョン20.1.0がGraalVM CEの最新版である。

  • GraalVMのダウンロード

    GraalVMのダウンロード

上記のサイトから使用しているOS用の.zipファイルまたは.tar.gzファイルをダウンロードしたら、インストールしたい場所に展開すればよい。筆者の環境はmacOSなので、「graalvm-ce-java11-darwin-amd64-20.1.0.tar.gz」をダウンロードした上で、/Library/Java/JavaVirtualMachines 以下に展開した。

上記のほかに、第2回で紹介したJDKのインストールツールであるSDKMANおよびShogunを使ってインストールすることもできる。

  • Shogunを使ったGraalVMのインストール

    Shogunを使ったGraalVMのインストール

インストールしたディレクトリ以下にある「/Contents/Home/bin」がjavacやjavaなどのコマンドのディレクトリである。ここには「jjs」と「js」というコマンドも含まれている。jjsは前回使用したNashorn用のコマンドラインツールである(GraalVMはJDK 11またはJDK 8ベースなのでNashornも付属する)。jsの方がGraalJSを使用するコマンドラインツールになっている。

/Library/Java/JavaVirtualMachines/graalvm-ce-java11-20.1.0/Contents/Home/bin$ ls
gu          javadoc     jdeprscan   jinfo       jps         jstat       node        rmic
jar         javap       jdeps       jjs         jrunscript  jstatd      npm         rmid
jarsigner   jcmd        jfr         jlink       js          jvisualvm   npx         rmiregistry
java        jconsole    jhsdb       jmap        jshell      keytool     pack200     serialver
javac       jdb         jimage      jmod        jstack      lli         polyglot    unpack200

Javaの実行環境としてGraalVMを使う場合、Java Scripting APIで使用するJavaScriptエンジンとしてGraalVMを指定することができる。

  • IntelliJ IDEAでJava開発環境としてGraalVMを使用する設定

    IntelliJ IDEAでJava開発環境としてGraalVMを使用する設定

Javaプログラム中でJavaScriptコードをGraalJSを使って実行したい場合には、次のようにScriptEngineのインスタンスを作成する際に、「nashorn」の代わりに「graal.js」を指定すればよい。

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class JavaScriptSample {
    public static void main(String[] args) {
        // JavaScriptエンジンを指定
        ScriptEngine scriptEngine =
            new ScriptEngineManager().getEngineByName("graal.js");
        try {
            // JavaScriptコードを実行
            scriptEngine.eval("function sum(a, b) { return a + b }");
            double v = (Double)scriptEngine.eval("sum(21, 22)");
            System.out.println(v);

        } catch (ScriptException e) {
            e.printStackTrace();
        }
    }
}

Java Scripting APIはJavaScriptエンジンには依存しない標準APIなので、このように使用するJavaScriptエンジンを切り替えたとしても、プログラムのほかの部分を書き換える必要はない。とはいえJava Acripting API自身も古いAPIなので、GraalVMではJava Scripting APIを使用しないJavaScriptの実行方法も提供している。次回は、そのようなNashornとGraalJSの違いについて紹介したい。