機械校正ツールであるRedPen(ライブデモ)は、デフォルトで内蔵している沢山の校正ロジックに加え、ユーザーがカスタムロジックを実装することができます。
自分で実装するにはJavaでValidatorというクラスを拡張すれば良いのですが、間口を広げるためにJavaScriptでもロジックを実装できるようにしました。
RedPen自体はJavaで実装しており、JavaからV8などを呼び出すのは大変なのでJava8に内蔵されているJavaScriptエンジンであるNashornを使いました。
あちこちの情報をかき集めて工夫をしたので、ここにまとめておきます。
やりたいことと、実現するためのコードを逆引き的に並べています。実現方法は全部違うけれども、どのコードもHello Nashornと出力するだけです。
・JavaScriptを呼び出す
・JavaScriptの関数をJavaから呼び出す
・JavaのstaticメソッドをJavaScriptから呼び出す
・JavaScriptからJavaのオブジェクトを参照する(バインドする)
・JavaScriptをコンパイルしてから呼び出す
・JavaオブジェクトのメソッドをJavaScriptの標準関数のように呼び出す
簡単にビルド、実行できるようまとめたものはGitHubに置いてあります。(ASLと書いてあるけど、創造性を微塵も感じさせないコードなので好き勝手コピペしていただいても大丈夫かと)
・JavaScriptを呼び出す
print関数を呼び出すだけのJavaScriptを実行します。getEngineByName()の引数はjsでもJavaScriptでもNashornでもok。
SimpleNashorn.java
public class SimpleNashorn {
public static void main(String... args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
// works also with "js" / "javascript"
ScriptEngine engine = manager.getEngineByName("nashorn");
// prints "Hello Nashorn"
engine.eval("print('Hello Nashorn');");
}
}
・JavaScriptの関数をJavaから呼び出す
JavaScript内で定義してある関数をJavaコードから呼び出す。invokeFunctionの第一引数が関数名、第二引数は可変長引数で、第一引数で指定した関数に渡すパラメータを任意の個数渡せる。
InvokeJavaScriptFunctions.java
public class InvokeJavaScriptFunction {
public static void main(String... args) throws ScriptException, NoSuchMethodException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
engine.eval("function hello(message){print(message);}");
Invocable invocable = (Invocable) engine;
// prints "Hello Nashorn"
invocable.invokeFunction("hello", "Hello Nashorn");
}
}
・JavaのstaticメソッドをJavaScriptから呼び出す
Java.typeっていうNashorn固有の機能を使います。
InvokeJavaStaticMethod.java
public class InvokeJavaStaticMethod {
public static void main(String... args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
// prints "Hello Nashorn"
engine.eval("Java.type('nashornsampler.InvokeJavaStaticMethod').hello('Hello Nashorn');");
}
public static void hello(String message) {
System.out.println(message);
}
}
・JavaScriptからJavaのオブジェクトを参照する(バインドする)
JavaScriptとJavaで相互に作用のあるコードを書くときはこんな風に。
BindJavaObject.java
public class BindJavaObject {
public static void main(String... args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
engine.put("myObj", new BindJavaObject());
// prints "Hello Nashorn"
engine.eval("myObj.hello();");
}
public void hello(){
System.out.println("Hello Nashorn");
}
}
・JavaScriptをコンパイルしてから呼び出す
JavaScriptコードを一旦Javaのバイトコードにコンパイルしてから実行します。繰り返し呼び出す場合は高速。Java8u40以降であればコンパイル結果はキャッシュされるのでJVMを再起動しても速攻でコンパイル結果が得られるらしい。
InvokeCompiledJavaScriptFunction.java
public class InvokeCompiledJavaScriptFunction {
public static void main(String... args) throws ScriptException, NoSuchMethodException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
CompiledScript compiledScript = ((Compilable) engine).compile("function hello(message){print(message);}");
compiledScript.eval();
Invocable invocable = (Invocable) engine;
// prints "Hello Nashorn"
invocable.invokeFunction("hello", "Hello Nashorn");
}
}
・JavaオブジェクトのメソッドをJavaScriptの標準関数のように呼び出す
JavaオブジェクトメソッドをJavaScriptよりobj.method()ではなく、単にmethod()と呼び出したい場合はこんな風に。
(恐らく要Java8u40以降)
BindJavaMethod.java
public class BindJavaMethod {
public static void main(String... args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
engine.put("toBeBound", new BindJavaMethod());
engine.eval("var hello = Function.prototype.bind.call(toBeBound.hello, toBeBound);");
// prints "Hello Nashorn"
engine.eval("hello('Hello Nashorn')");
}
public void hello(String message) {
System.out.println(message);
}
}
関連記事:
・Heroku Buttonで簡単にHerokuにデプロイ #herokujp – #侍ズム
・WebアプリケーションをIntelliJ IDEAからHerokuへデプロイする #herokujp #jbugj – #侍ズム
・Java WebアプリケーションをHerokuへデプロイする #herokujp – #侍ズム
・Getting Started with Java on Heroku | Heroku Dev Center
・RedPen を公開しました (ベータバージョン) | Advanced Technology Lab
・社内共有会で使用した RedPen 資料と進捗 | Advanced Technology Lab