我怎么能通过一个适当的方法参考,所以Nashorn可以执行它?

我正在尝试编写一个库,让我通过Nashorn Javascript引擎执行JSON逻辑规则。

我现在的问题是围绕着我创建的JSObject包装器来处理将数据从Java / Kotlin移动到脚本引擎中。

如果一个数组被传入,例如[true]它将被包装,并且json-logic脚本会接收它,看它是一个数组,并且尝试运行下面的代码:

 if(Array.isArray(logic)) { return logic.map(function(l) { return jsonLogic.apply(l, data); }); } 

当调用.map函数时,Nashorn会调用getMember("map")来获取可执行的函数。

这是我卡住的地方。 我一直无法找到任何合适的语法给Nashorn一个方法或方法的引用,可以作为它的地图函数的接收器调用。

代码可以在这里找到: https : //github.com/deinspanjer/json-logic-java有一些基本的单元测试,包括发生问题的单元测试, JavaJsonLogicTest.simpleApplyJEJO() 。 破解的代码行是com/jsonlogic/JSObjectWrappers.kt:97

我非常感谢你的帮助。

更新:基于接受的答案,这里是工作Kotlin版本的代码:

 package com.jsonlogic import jdk.nashorn.api.scripting.AbstractJSObject import jdk.nashorn.api.scripting.JSObject import java.util.function.Function import javax.script.ScriptEngineManager fun main(args: Array<String>) { val m = ScriptEngineManager() val e = m.getEngineByName("nashorn") // The following JSObject wraps this list val l = mutableListOf<Any>() l.add("hello") l.add("world") l.add(true) l.add(1) val jsObj = object : AbstractJSObject() { override fun getMember(name: String?): Any? { if (name == "map") { // return a functional interface object - nashorn will treat it like // script function! return Function { callback: JSObject -> val res = l.map { // call callback on each object and add the result to new list callback.call(null, it) } // return fresh list as result of map (or this could be another wrapper) res } } else { // unknown property return null } } } e.put("obj", jsObj) // map each String to it's uppercase and print result of map e.eval("print(obj.map(function(x) '\"'+x.toString()+'\"'))"); } 

JSObject.getMember可以返回任何脚本“可调用”。 这可能是另一个为isFunction或Java功能接口对象返回“true”的JSObject。 几个简单的Java示例程序在这里:

 import javax.script.*; import jdk.nashorn.api.scripting.*; import java.util.*; public class Main { public static void main(String[] args) throws Exception { ScriptEngineManager m = new ScriptEngineManager(); ScriptEngine e = m.getEngineByName("nashorn"); // The following JSObject wraps this list List<String> l = new ArrayList(); l.add("hello"); l.add("world"); JSObject jsObj = new AbstractJSObject() { @Override public Object getMember(String name) { // return a "function" object for "map" if (name.equals("map")) { return new AbstractJSObject() { @Override public Object call(Object thiz, Object... args) { // first argument is the callback passed from script JSObject callable = (JSObject)args[0]; List<Object> res = new ArrayList<>(); for (Object obj : l) { // call callback on each object and add the result to new list res.add(callable.call(null, obj)); } // return fresh list as result of map (or this could be another wrapper) return res; } @Override public boolean isFunction() { return true; } }; } else { // unknown property return null; } } }; e.put("obj", jsObj); // map each String to it's uppercase and print result of map e.eval("print(obj.map(function(x) x.toUpperCase()))"); } } 

上面的例子为“map”属性返回一个可调用的JSObject。 返回的“函数”本身使用回调函数作为参数。 所有脚本函数(和对象)都作为JSObjects传递给Java代码,因此'map'代码将第一个参数强制转换为JSObject以调用脚本回调函数。

上面的示例修改为使用功能接口如下所示:

 import javax.script.*; import jdk.nashorn.api.scripting.*; import java.util.*; import java.util.function.*; public class Main2 { public static void main(String[] args) throws Exception { ScriptEngineManager m = new ScriptEngineManager(); ScriptEngine e = m.getEngineByName("nashorn"); // The following JSObject wraps this list List<String> l = new ArrayList(); l.add("hello"); l.add("world"); JSObject jsObj = new AbstractJSObject() { @Override public Object getMember(String name) { if (name.equals("map")) { // return a functional interface object - nashorn will treat it like // script function! return (Function<JSObject, Object>)callback -> { List<Object> res = new ArrayList<>(); for (Object obj : l) { // call callback on each object and add the result to new list res.add(callback.call(null, obj)); } // return fresh list as result of map (or this could be another wrapper) return res; }; } else { // unknown property return null; } } }; e.put("obj", jsObj); // map each String to it's uppercase and print result of map e.eval("print(obj.map(function(x) x.toUpperCase()))"); } } 

希望以上样本可以帮助您为您的场景提供Kotlin版本。