[Java8] Java上でJavaScriptを動かす


# 目的

+ 【追記】Java 8 で追加された以下の機能ですが、Java 11 で廃止されました。

- Java6 あたりから、Java内にJavaScriptエンジン(Rhino)が追加されています。
- Java8 ではJavaScriptエンジン(Nashorn)の性能が向上したという話なので、いまさらながら少し動かしてみました
- でも性能測定とかはしません
- メソッドの詳細な説明もしないです

# 概要

Java での JavaScript サポートは、ライブラリから扱える `javax.script` パッケージと、そのコマンドライン版があります。

実際には JavaScript 以外のスクリプト言語も対応が予定されているみたいですが、現時点では JavaScript のみが対応されているみたいです。

## コマンドライン版

コマンドライン版は、Java6, Java7 では JDKの bin ディレクトリに `jrunscript` というコマンドがありました。これは Java8 でも残っているみたいです。

Java8 からは追加で JRE の bin ディレクトリに `jjs` というコマンドがあります。
開発環境(JDK)ではなく利用環境(JRE)だけでも使えるようになったのかな。

今回は触っていません。

## javax.script パッケージ

JavaScript のソースの文字列から実行することができます（ファイルから読み込んで実行も可能）。

また、Java と JavaScript でデータのやり取りやメソッドの呼び出しなども可能です。

# サンプルソース

とりあえず動かしてみました。例外処理は手を抜いています。

```java
package test.javascript;

import java.util.Date;
import java.util.List;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;

/** Java と JavaScript の連携 */
public class JavaScriptTest {

	public static void main(String[] args) throws Exception {
		System.out.println("java.version: " + System.getProperty("java.version"));

        // 対応している ScriptEngine の情報を出力
		ScriptEngineManager manager = new ScriptEngineManager();
		List<ScriptEngineFactory> engineFactories = manager.getEngineFactories();
		for (ScriptEngineFactory factory : engineFactories) {
			System.out.println("Engine: " + factory.getEngineName()
					+ ", Version: " + factory.getEngineVersion());
			System.out.println("Language: " + factory.getLanguageName()
					+ ", Version: " + factory.getLanguageVersion());
			System.out.println("Extensions: " + factory.getExtensions());
			System.out.println("MimeTypes: " + factory.getMimeTypes());
			System.out.println("Names: " + factory.getNames());
			System.out.println();
		}
		ScriptEngine engine = manager.getEngineByName("JavaScript");

		// JavaScript の実行
		engine.eval("var message = 'Hello, I am JavaScript.'");
		engine.eval("print('#1: ' + message)");

		// Java のオブジェクトを JavaScript に渡してみる
		engine.put("message2", "Hello, I am Java8.");
		engine.put("today", new Date());
		engine.eval("print('#2: ' + message2 + ' now : ' + today.toString())");

		// JavaScript から Java のメソッドを使用
		engine.eval("var obj = Java.type('test.javascript.JavaScriptTest');"
				+ "print('#3: ' + obj.getMessage());");
		engine.eval("obj.printMessage('Good afternoon.');");

		// Java から JavaScript の値を取得
		engine.eval("var message3 = 'Good evening.';");
		Object message3 = engine.get("message3");
		System.out.println("#5: " + message3);

		// Java から JavaScript の関数を呼び出し
		if (engine instanceof Invocable) {
			Invocable invocable = (Invocable) engine;
			engine.eval("var func = function(arg) { print('#6: ' + arg);}");
			invocable.invokeFunction("func", "Good night.");
		}
	}

	/** メッセージを返す */
	public static String getMessage() {
		return "Good morning.";
	}

	/** メッセージを出力 */
	public static void printMessage(String message) {
		System.out.println("#4: " + message);
	}
}
```

動作結果はこんな感じ。

```
java.version: 1.8.0_65
Engine: Oracle Nashorn, Version: 1.8.0_65
Language: ECMAScript, Version: ECMA - 262 Edition 5.1
Extensions: [js]
MimeTypes: [application/javascript, application/ecmascript, text/javascript, text/ecmascript]
Names: [nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript]

#1: Hello, I am JavaScript.
#2: Hello, I am Java8. now : Thu Nov 05 22:51:09 JST 2015
#3: Good morning.
#4: Good afternoon.
#5: Good evening.
#6: Good night.
```

# 落書き

- Rhino の読みは「ライノー」で、英語で犀のこと
- Nashorn のよみは「ナースホルン」でドイツ語で犀のこと
- ネタ元はオライリーのJavaScript本なんでしょうね