首页 文章

我怎样才能传递正确的方法引用,以便Nashorn可以执行它?

提问于
浏览
2

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

我现在的问题是围绕我创建的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提供一个方法或方法引用,可以将其作为其map函数的接收者调用 .

代码可在此处获得:https://github.com/deinspanjer/json-logic-java有一些基本的单元测试,包括显示问题的单元测试, JavaJsonLogicTest.simpleApplyJEJO() . 被破坏的代码行是 com/jsonlogic/JSObjectWrappers.kt:97 .

我非常感谢你的帮助 .

UPDATE: 根据接受的答案,这里是代码的工作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()+'\"'))");
}

1 回答

  • 4

    JSObject.getMember可以返回任何脚本“callable” . 这可能是另一个为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 . 返回的“函数”本身使用回调函数作为参数 . 所有脚本函数(和对象)都作为JSObject传递给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版本 .

相关问题