JavaスクリプトAPIは、javax.script
パッケージのクラスとインタフェースで構成されます。これは、ScriptEngineManager
クラスを出発点とする比較的小規模で単純なパッケージです。ScriptEngineManager
オブジェクトは、JARファイル・サービス検出メカニズムによってスクリプト・エンジンを検出し、特定のスクリプト言語で記述されたスクリプトを解釈するScriptEngine
オブジェクトをインスタンス化できます。
Nashornエンジンは、Java SE Development Kit (JDK)にバンドルされているデフォルトのECMAScript (JavaScript)エンジンです。Nashornエンジンは、オラクル社がOpenJDKプロジェクト(Project Nashorn)の一環として完全にJavaで開発しました。
NashornはJavaスクリプトAPIで使用されるデフォルトのECMAScriptエンジンですが、JSR 223に準拠する任意のスクリプト・エンジンを使用することも、独自のエンジンを実装することもできます。このドキュメントでは、JSR 223に準拠するスクリプト・エンジンの実装について説明しませんが、もっとも基本的なレベルでは、javax.script.ScriptEngine
およびjavax.script.ScriptEngineFactory
インタフェースを実装する必要があります。抽象クラスjavax.script.AbstractScriptEngine
は、ScriptEngine
インタフェースのいくつかのメソッドに有用なデフォルトを提供します。
JavaスクリプトAPIを使用するには:
ScriptEngineManager
オブジェクトを作成します。
マネージャからScriptEngine
オブジェクトを取得します。
スクリプト・エンジンのeval()
メソッドを使用してスクリプトを評価します。
次の例は、JavaでJavaスクリプトAPIを使用する方法を示しています。例を簡単にするため、例外は処理されていません。ただし、JavaスクリプトAPIによってスローされるチェック例外と実行時例外が存在するため、それらを適切に処理する必要があります。すべての例で、ScriptEngineManager
クラスのインスタンスとgetEngineByName()
メソッドを使用して、Nashornエンジン(ScriptEngine
クラスのインスタンス)を要求します。指定されたエンジンが存在しない場合は、null
を返します。Nashornエンジンの使用方法の詳細は、『Nashornユーザーズ・ガイド』を参照してください。
注意:
各ScriptEngine
オブジェクトには、固有の変数スコープがあります。「複数スコープの使用」を参照してください。
文の評価
この例では、スクリプト・エンジン・インスタンスのeval()
メソッドを呼び出し、String
オブジェクトのJavaScriptコードを実行します。
import javax.script.*; public class EvalScript { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); // evaluate JavaScript code engine.eval("print('Hello, World')"); } }
スクリプト・ファイルの評価
この例では、eval()
メソッドがscript.js
という名前のファイルからJavaScriptコードを読み取るFileReader
オブジェクトを取ります。様々な入力ストリーム・オブジェクトをリーダーとしてラップすることにより、ファイル、URLおよびその他のリソースからスクリプトを実行できます。
import javax.script.*; public class EvalFile { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); // evaluate JavaScript code engine.eval(new java.io.FileReader("script.js")); } }
Javaオブジェクトをグローバル変数として公開する
この例では、File
オブジェクトを作成し、put()
メソッドを使用してそれをfile
という名前のグローバル変数としてエンジンに公開します。次に、この変数にアクセスしてgetAbsolutePath()
メソッドを呼び出すJavaScriptコードを指定して、eval()
メソッドを呼び出します。
注意:
変数として公開されたJavaオブジェクトのフィールドにアクセスしてメソッドを呼び出す構文は、スクリプト言語によって異なります。この例では、Javaによく似たJavaScript構文を使用します。
import javax.script.*; import java.io.*; public class ScriptVars { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); // create File object File f = new File("test.txt"); // expose File object as a global variable to the engine engine.put("file", f); // evaluate JavaScript code and access the variable engine.eval("print(file.getAbsolutePath())"); } }
スクリプト関数の呼出し
この例では、1つのパラメータを持つ関数を定義するJavaScriptコードを指定してeval()
メソッドを呼び出します。次に、Invocable
オブジェクトを作成し、そのinvokeFunction()
メソッドを使用して関数を呼び出します。
注意:
すべてのスクリプト・エンジンがInvocable
インタフェースを実装しているわけではありません。この例ではNashornエンジンを使用しており、このエンジンによって前に評価されたスクリプト内の関数を呼び出すことができます。
import javax.script.*; public class InvokeScriptFunction { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); // evaluate JavaScript code that defines a function with one parameter engine.eval("function hello(name) { print('Hello, ' + name) }"); // create an Invocable object by casting the script engine object Invocable inv = (Invocable) engine; // invoke the function named "hello" with "Scripting!" as the argument inv.invokeFunction("hello", "Scripting!"); } }
スクリプト・オブジェクトのメソッドの呼出し
この例では、1つのメソッドを持つオブジェクトを定義するJavaScriptコードを指定してeval()
メソッドを呼び出します。次に、スクリプト・エンジンのget()
メソッドを使用して、このオブジェクトをスクリプトからJavaアプリケーションに公開します。次に、Invocable
オブジェクトを作成し、そのinvokeMethod()
メソッドを使用してスクリプト・オブジェクトに定義されたメソッドを呼び出します。
注意:
すべてのスクリプト・エンジンがInvocable
インタフェースを実装しているわけではありません。この例ではNashornエンジンを使用しており、このエンジンによって前に評価されたスクリプト内のメソッドを呼び出すことができます。
import javax.script.*; public class InvokeScriptMethod { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); // evaluate JavaScript code that defines an object with one method engine.eval("var obj = new Object()"); engine.eval("obj.hello = function(name) { print('Hello, ' + name) }"); // expose object defined in the script to the Java application Object obj = engine.get("obj"); // create an Invocable object by casting the script engine object Invocable inv = (Invocable) engine; // invoke the method named "hello" on the object defined in the script // with "Script Method!" as the argument inv.invokeMethod(obj, "hello", "Script Method!"); } }
スクリプト関数を使用したJavaインタフェースの実装
この例では、関数を定義するJavaScriptコードを指定してeval()
メソッドを呼び出します。次に、Invocable
オブジェクトを作成し、そのgetInterface()
メソッドを使用してRunnable
インタフェース・オブジェクトを作成します。このインタフェースのメソッドは、一致する名前を持つスクリプト関数によって実装されます(この場合は、run()
関数を使ってインタフェース・オブジェクトのrun()
メソッドが実装されます)。最後に、スクリプト関数を実行する新しいスレッドを開始します。
import javax.script.*; public class ImplementRunnable { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); // evaluate JavaScript code that defines a function with one parameter engine.eval("function run() { print('run() function called') }"); // create an Invocable object by casting the script engine object Invocable inv = (Invocable) engine; // get Runnable interface object Runnable r = inv.getInterface(Runnable.class); // start a new thread that runs the script Thread th = new Thread(r); th.start(); th.join(); } }
スクリプト・オブジェクトのメソッドを使用したJavaインタフェースの実装
この例では、1つのメソッドを持つオブジェクトを定義するJavaScriptコードを指定してeval()
メソッドを呼び出します。次に、スクリプト・エンジンのget()
メソッドを使用して、このオブジェクトをスクリプトからJavaアプリケーションに公開します。次に、Invocable
オブジェクトを作成し、そのgetInterface()
メソッドを使用してRunnable
インタフェース・オブジェクトを作成します。このインタフェースのメソッドは、一致する名前を持つスクリプト・オブジェクトのメソッドによって実装されます(この場合は、obj
オブジェクトのrun
メソッドを使ってインタフェース・オブジェクトのrun()
メソッドが実装されます)。最後に、スクリプト・オブジェクトのメソッドを実行する新しいスレッドを開始します。
import javax.script.*; public class ImplementRunnableObject { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); // evaluate JavaScript code that defines a function with one parameter engine.eval("var obj = new Object()") engine.eval("obj.run = function() { print('obj.run() method called') }"); // expose object defined in the script to the Java application Object obj = engine.get("obj"); // create an Invocable object by casting the script engine object Invocable inv = (Invocable) engine; // get Runnable interface object Runnable r = inv.getInterface(obj, Runnable.class); // start a new thread that runs the script Thread th = new Thread(r); th.start(); th.join(); } }
複数スコープの使用
この例では、スクリプト・エンジンのput()
メソッドを使用して変数x
をString
オブジェクトhello
に設定します。次に、eval()
メソッドを使用して変数をデフォルトのスコープで出力します。次に、異なるスクリプト・コンテキストを定義し、そのスコープを使用して同じ変数を異なる値(String
オブジェクトworld
)に設定します。最後に、異なる値を表示する新しいスクリプト・コンテキストで変数を出力します。
単一のスコープは、javax.script.Bindings
インタフェースのインスタンスです。このインタフェースは、java.util.Map<String, Object>
インタフェースから派生します。スコープは、名前が空でもnullでもないString
オブジェクトである名前と値のペアのセットです。javax.script.ScriptContext
インタフェースは、各スコープにBindings
が関連付けられている複数のスコープをサポートします。デフォルトでは、すべてのスクリプト・エンジンにデフォルトのスクリプト・コンテキストがあります。デフォルトのスクリプト・コンテキストには、staticフィールドENGINE_SCOPE
で表されるスコープが少なくとも1つ存在します。スクリプト・コンテキストでサポートされる様々なスコープをgetScopes()
メソッドで取得できます。
import javax.script.*; public class MultipleScopes { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("nashorn"); // set global variable engine.put("x","hello"); // evaluate JavaScript code that prints the variable (x = "hello") engine.eval("print(x)"); // define a different script context ScriptContext newContext = new SimpleScriptContext(); newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE); // set the variable to a different value in another scope engineScope.put("x", "world"); // evaluate the same code but in a different script context (x = "world") engine.eval("print(x)", newContext);