使Javascript函数可用于Java代码 问题描述
一个有点做作的例子来说明我的问题。想象一下,我们有一些javascript函数库,这些函数库已经由大量前端开发人员每天维护和更新。具体来说,想象这样一个函数如下所示:使Javascript函数可用于Java代码 问题描述,java,javascript,Java,Javascript,一个有点做作的例子来说明我的问题。想象一下,我们有一些javascript函数库,这些函数库已经由大量前端开发人员每天维护和更新。具体来说,想象这样一个函数如下所示: function employeesForStore(store) { var dictionary = { "downtown": ["Joe", "Mary", "Steve"], "uptown": ["Jules", "Vincent", "Matt"], // an
function employeesForStore(store) {
var dictionary = {
"downtown": ["Joe", "Mary", "Steve"],
"uptown": ["Jules", "Vincent", "Matt"],
// and so on for hundreds of locations
};
return dictionary[store];
}
注意:请忽略此函数实现的详细信息。实际函数可能比简单的JSON字典查找复杂得多,并且假设我们不知道有关js函数的任何实现细节。我们所知道的只是它接受一个字符串参数并返回字符串和字符串数组
现在我们想在Java代码中利用这个函数。也就是说,在Java代码中,我们希望“加载”这个函数,然后能够多次调用它,传递它String
args并接收String[]
或ArrayList
结果
从搜索SO和google到目前为止,我了解到这将涉及使用:
javax.script.ScriptEngineManager
javax.script.ScriptEngine
- 可能还有
,用于将值传递到函数并接收结果李>scriptEngine.getContext()
employeesForStore(“downtown”)
并将其结果存储在本地java字符串[]
或列表
中名为downtownResults
的变量中employeesForStore(“uptown”)
并将其存储在变量uptownResults
这涵盖了所要求的示例。创建一个接口,作为JavaScript代码的一部分 下面是一个使用嵌入Oracle Java 1.7实现中的Rhino实现的示例:
package demo;
import java.io.*; import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import javax.script.*;
public class StoreData {
public static interface Stores {
public String[] employees(String store);
}
public static Stores stores() throws IOException, ScriptException {
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem.getEngineByName("JavaScript");
AtomicReference<Stores> ref = new AtomicReference<>();
engine.put("ref", ref);
String adapt = "ref.set("
+ "new Packages.demo.StoreData.Stores({employees:employeesForStore})"
+ ");";
try (Reader myFns = new FileReader("my_functions.js")) { // TODO encoding
engine.eval(myFns);
engine.eval(adapt);
return ref.get();
}
}
public static void main(String[] args) throws IOException, ScriptException {
List<String> employees = Arrays.asList(stores().employees("uptown"));
System.out.println(employees);
}
}
软件包演示;
导入java.io.*;导入java.util.*;
导入java.util.concurrent.AtomicReference;
导入javax.script.*;
公共类存储数据{
公共静态接口存储{
公共字符串[]员工(字符串存储);
}
public static Stores Stores()引发IOException、ScriptException{
ScriptEngineManager sem=新ScriptEngineManager();
ScriptEngine=sem.getEngineByName(“JavaScript”);
AtomicReference ref=新的AtomicReference();
发动机。放置(“参考”,参考);
String adapt=“ref.set(”
+“新包.demo.StoreData.Stores({employees:employeesForStore})”
+ ");";
试试(Reader myFns=newfilereader(“my_functions.js”){//TODO编码
发动机评估(myFns);
发动机评估(自适应);
返回ref.get();
}
}
公共静态void main(字符串[]args)引发IOException、ScriptException{
List employees=Arrays.asList(stores().employees(“住宅区”));
系统输出打印LN(员工);
}
}
通过指定接口,我们让Rhino将JavaScript类型强制为Java类型(String、String[]等)
JRE规范规定了应该提供哪些脚本引擎,因此依赖外部引擎可能是明智的。我不知道你是否会改变这一点。在你的情况下,你只是在访问一个js对象,你可以将其序列化为JSON,然后用Java解析它。@moonwave99,忽略
employeesForStore
是如何实现的。我们不知道,这只是一个简单的例子。实际上,该函数可以在内部完全不同地实现,并且可能比简单的JSON字典查找复杂得多。(他们也建议使用犀牛)谢谢!你能解释一下adapt
是怎么回事吗?它看起来像java代码,但是JS引擎正在评估它。是java还是js?似乎参数{employees:employeesForStore}
以某种方式将javaemployees
方法映射到jsemployeesForStore
函数,这是否正确?到底是怎么回事?AtomicReference
是负责映射还是其他什么+1已获取大量信息。存储。员工
映射到员工存储
。Rhino动态提供存储
实现-请参阅。AtomicReference
只是一种在创建实例后获取实例引用的方法(不是唯一的方法)。在这方面,AtomicReference
类型没有什么特别之处。好吧,那么我们创建的JS脚本引擎能够交替使用java和JS代码吗?是的,Rhino通常会将JavaScript类型强制为java类型,例如,当它调用强类型java方法时。