LoginSignup
4
1

More than 5 years have passed since last update.

Javaの一部の処理をJavaScriptに委譲する

Last updated at Posted at 2018-06-16

「Javaの一部の処理を外部から注入できないか?」ということで調べた結果の個人的メモです。

方法

調べてみたらJava上のJavaScript スクリプティングエンジン(Nashorn)というものがあったのでそれを使用してみました。
Nashornは、Java SE8のjavax.scriptパッケージから呼び出すことができます。
※Java SE6,7では、Mozillaが実装したJavaScript スクリプティングエンジン(Rhino)が使われています。

サンプルコード

Listのフィルタ処理をJavaScriptに委譲するサンプルコードです。

Main.java
public class Main {

    public static void main(String[] args) throws Exception {
        List<Person> list = Arrays.asList(new Person("a", 1), new Person("b", 2), new Person("c", 3));
        // JavaScriptのフィルタ処理を委譲する
        List<Person> resultList = list.stream().filter(e -> eval(e)).collect(Collectors.toList());
        // フィルタ前のリストを表示
        System.out.println("フィルタ前: " + list);
        // フィルタ後のリストを表示
        System.out.println("フィルタ後: " + resultList);
    }

    /**
     * JavaScriptの実行結果を評価する
     * @param person
     * @return true/false
     */
    public static boolean eval(Person person) {
        boolean result = false;
        try {
            ScriptEngineManager manager = new ScriptEngineManager();
            // JavaScriptエンジンを作成する
            ScriptEngine engine = manager.getEngineByName("javascript");
            // Java側のオブジェクトをJavaScriptの変数に設定する
            engine.put("person", person);
            // ファイルからJavaScriptファイルを読み込む
            Reader script = new InputStreamReader(Main.class.getResourceAsStream("sample.js"));
            // JavaScriptを実行する
            result = Boolean.valueOf(true).equals(engine.eval(script));
        } catch(ScriptException ex) {
            ex.printStackTrace();
        }
        return result;

    }
}

リスト内の要素となるJavaオブジェクト。
JavaScriptからフィールド変数にアクセスできるようにpublicなgetterを定義しています。

Person.java
public class Person {
    private String name;
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public Integer getAge() {
        return age;
    }
    public String toString() {
        return "{ name: " + this.name + ", age: " + this.age + "}";
    }
}

以下のsample.jsで、Java側のfilterメソッドの処理を行っています。
Javaから渡されたpersonオブジェクトのフィールドにアクセスすることもできました。

sample.js
// personはJava側から渡されたリストの要素
// nameフィールドにアクセスし、判定式に利用している
person.name === 'a' || person.name === 'b';

処理結果

上記のサンプルコードの処理結果は以下となります。
sample.jsの評価結果により、Listの内容がフィルタされたことが分かります。

フィルタ前: [{ name: a, age: 1}, { name: b, age: 2}, { name: c, age: 3}]
フィルタ後: [{ name: a, age: 1}, { name: b, age: 2}]

感想

今回のケースのような使い方をすれば、
例えば画面上からユーザがフィルタリング条件をその都度変更できるリストを作れて便利だなと思いました。

備考

以下、参考リンクです。
Java の上の JavaScript エンジン Nashorn の基本
OpenJDK wiki >> Nashorn

※追記:Nashornは非推奨になので使わない方が良さそうです。
JavaでJavaScriptを実行する「Nashorn」が非推奨に、ECMAScriptの速い進化に追いつけないと。代替案はGraalVM

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1