在Nashorn中调用Java子类的函数

时间:2017-04-12 18:51:29

标签: javascript java java-8 nashorn

我有一个类似于这样的JavaScript脚本:

function run(database) {
    var result = database.query("query", "some resource name");
    //operations on result
    return result;
}

我有Java代码执行类似这样的脚本:

public Object execute(String script, Database database) {
    NashornScriptEngineFactory nsef = new NashornScriptEngineFactory();
    ScriptEngine engine = nsef.getScriptEngine();
    try {
        engine.eval(script);
        Invocable invocable = (Invocable) engine;
        return invocable.invokeFunction("run", database);
    } catch(ScriptException e) {
        throw new RuntimeException(e);
    }
}

Database是一个包含多个方法定义的接口,但包含query方法。我使用execute的实施方式调用Database,将其称为DatabaseImpl 具有query方法。这将是多态的,并且该脚本应该知道传递给它的Database实例上有哪些可用的方法。我决定不使用泛型,因为它们在运行时被删除,因此JavaScript无论如何都无法使用它们,所以由脚本编写者来确定类型是正确的。

但是,当我运行此代码时,我得到以下异常:

javax.script.ScriptException: TypeError: database.query is not a function in <eval> at line number 25

基本上,要点是,我有一个实现接口的对象,并调用特定实例实现的方法,但不是接口定义的一部分。我的印象是,这应该仍然有效,但事实并非如此。对我来说,我需要在脚本中进行子播放才能访问query方法(即使可能吗?)也没有多大意义,为什么我会收到此错误?是因为该方法不能从接口定义中获得吗?有解决方法吗?

感谢。

1 个答案:

答案 0 :(得分:1)

这是主要课程:

package so;
import java.io.InputStreamReader;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Nashorn {
    public static void main(String[] args) {
        try (InputStreamReader in = resource()) {
            ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
            engine.eval(in);
            Invocable invocable = (Invocable) engine;
            Database database = new DatabaseImpl();
            Object x = invocable.invokeFunction("run", database);
            System.out.println(x);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static InputStreamReader resource() throws Exception {
        return new InputStreamReader(Nashorn.class.getResourceAsStream("db.js"), "utf-8");
    }

}

接口和实施

package so;

public interface Database {
    void connect();
}

package so;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DatabaseImpl implements Database {

    @Override
    public void connect() {
        System.out.println("Connecting");
    }

    public List<?> query(String ... stmt){
        List<String> lst = new ArrayList<>(); 
        lst.addAll(Arrays.asList(stmt));
        lst.addAll(Arrays.asList("A","B","C"));
        return lst;
    }

}

javascript文件(so / db.js)

function run(database) {
    var result = database.query("query", "some resource name");
    //operations on result
    return result;
}

运行结果:

[query, some resource name, A, B, C]

它基本上有效。