在 Nashorn 的 Java 子类上调用函数
Invoking function on Java subclass in 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
方法。我用 Database
的实现调用 execute
,称之为 DatabaseImpl
, 有 query
方法。这将是多态的,脚本应该知道传递给它的 Database
实例上有哪些方法可用。我决定不使用泛型,因为它们在 运行 时被删除,所以 Java 脚本无论如何都无法使用它们,所以由脚本编写者来获得正确的类型。
但是,当我 运行 这段代码时,出现以下异常:
javax.script.ScriptException: TypeError: database.query is not a function in <eval> at line number 25
基本上,要点是,我有一个实现接口的对象,并调用特定实例实现的方法,但不是接口定义的一部分。我的印象是这应该仍然有效,但事实并非如此。我需要在脚本中进行子广播才能访问 query
方法(这甚至可能吗?),这对我来说意义不大,那么为什么我会收到此错误?是因为该方法在接口定义中不可用吗?有解决方法吗?
谢谢。
这是主要的class:
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]
基本上可以了。
我有一个 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
方法。我用 Database
的实现调用 execute
,称之为 DatabaseImpl
, 有 query
方法。这将是多态的,脚本应该知道传递给它的 Database
实例上有哪些方法可用。我决定不使用泛型,因为它们在 运行 时被删除,所以 Java 脚本无论如何都无法使用它们,所以由脚本编写者来获得正确的类型。
但是,当我 运行 这段代码时,出现以下异常:
javax.script.ScriptException: TypeError: database.query is not a function in <eval> at line number 25
基本上,要点是,我有一个实现接口的对象,并调用特定实例实现的方法,但不是接口定义的一部分。我的印象是这应该仍然有效,但事实并非如此。我需要在脚本中进行子广播才能访问 query
方法(这甚至可能吗?),这对我来说意义不大,那么为什么我会收到此错误?是因为该方法在接口定义中不可用吗?有解决方法吗?
谢谢。
这是主要的class:
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]
基本上可以了。