Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Nashorn之间无缝地传递数组和列表_Java_Arrays_Nashorn - Fatal编程技术网

Java 在Nashorn之间无缝地传递数组和列表

Java 在Nashorn之间无缝地传递数组和列表,java,arrays,nashorn,Java,Arrays,Nashorn,我知道您可以在Nashorn中使用Java数组,并且有很多例子说明了如何做到这一点。对于我来说,标准方法的问题在于它使javascript代码明确地知道它的运行时环境。目前我有一个利用Rhino的解决方案,它可以在Java类型和本机javascript类型之间无缝转换 对于Rhino,我通过实现org.mozilla.javascript.ContextFactory和org.mozilla.javascript.WrapFActory并在调用makeContext时在Context上设置Wra

我知道您可以在Nashorn中使用Java数组,并且有很多例子说明了如何做到这一点。对于我来说,标准方法的问题在于它使javascript代码明确地知道它的运行时环境。目前我有一个利用Rhino的解决方案,它可以在Java类型和本机javascript类型之间无缝转换

对于Rhino,我通过实现
org.mozilla.javascript.ContextFactory
org.mozilla.javascript.WrapFActory
并在调用
makeContext
时在
Context
上设置
WrapFActory来实现这一点。此WrapFactory实现负责Java数组和列表与本机javascript数组和列表之间的转换。它还愤怒地提到,我必须从JDK获得Rhino源代码才能使这种方法发挥作用

我需要为纳肖恩找到一个类似的解决方案。下面是一个我正在努力完成的例子

public static void main(String args[]) {
    NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
    ScriptEngine engine = factory.getScriptEngine();
    try {
        engine.eval("function print_array(arr) { print(arr); }");
        engine.eval("function print_native() { print_array([1, 2, 3, 4]); }");
        Invocable invocable = (Invocable) engine;
        invocable.invokeFunction("print_array", new int[]{1, 2, 3, 4});
        invocable.invokeFunction("print_array", Arrays.asList(1, 2, 3, 4));
        invocable.invokeFunction("print_native");
    } catch (ScriptException | NoSuchMethodException e) {
        e.printStackTrace();
    }
}
这段代码的输出是

[I@169e6180

[1,2,3,4]

1,2,3,4

我正在寻找一种实现ScriptObjectMirror的方法,假设这是正确的,这将使这三个
invokeFunction
调用的输出相同

我尝试在
ScriptUtils
上使用
wrap
函数,但结果仍然是错误的

更新

我试图创建一个类型为
Invocable
的动态代理,并在
InvocationHandler
中进行转换。要使用Nashorn创建NativeArray,似乎应该使用
jdk.Nashorn.internal.objects.Global.allocate
,但这总是会引发异常

Global.allocate(new int[] {1, 2, 3, 4})
提高

Exception in thread "main" java.lang.NullPointerException
    at jdk.nashorn.internal.objects.Global.instance(Global.java:491)
    at jdk.nashorn.internal.objects.NativeArray.<init>(NativeArray.java:141)
    at jdk.nashorn.internal.objects.Global.allocate(Global.java:1584)
线程“main”java.lang.NullPointerException中的异常 位于jdk.nashorn.internal.objects.Global.instance(Global.java:491) 位于jdk.nashorn.internal.objects.NativeArray。(NativeArray.java:141) 位于jdk.nashorn.internal.objects.Global.allocate(Global.java:1584)
我认为实现AbstractJSObject需要付出艰苦的努力。我认为很多像getMember这样的函数都可以通过Refelction来实现。但是如果有人认为它是一个JS数组并尝试扩展原型,你会怎么做呢?你也想处理这个问题吗?在这种情况下,我会将JS数组作为属性实现在一个列表中,如包装类并将所有集合/添加委托给更新JS对象的JS函数

解决方案1:

public static void main(String args[]) {
        NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
        ScriptEngine engine = factory.getScriptEngine();

        try {
            engine.eval("function print_array(arr) { print(arr); for(var i=0; i<arr.length; i++) {print(arr[i]);}}");
            engine.eval("function print_native() { print_array([1, 2, 3, 4]); }");
            engine.eval("function get_native() { return [1, 2, 3, 4]; }");
            Invocable invocable = (Invocable) engine;
            invocable.invokeFunction("print_array", new int[]{1, 2, 3, 4});
            invocable.invokeFunction("print_array", Arrays.asList(1, 2, 3, 4));
            invocable.invokeFunction("print_array", new Foo());
            invocable.invokeFunction("print_native");

            ScriptObjectMirror a = (ScriptObjectMirror) invocable.invokeFunction("get_native");
            System.out.println(invocable.invokeFunction("get_native"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class Foo extends AbstractJSObject {
        Map<Integer, Object> arrayValues = new HashMap<>();

        public Foo() {
            arrayValues.put(0, 1);
            arrayValues.put(1, 2);
            arrayValues.put(2, 3);
        }
        @Override
        public Object call(Object thiz, Object... args) {
            System.out.println("call");
            return super.call(thiz, args);
        }

        @Override
        public Object newObject(Object... args) {
            System.out.println("new Object");
            return super.newObject(args);
        }

        @Override
        public Object eval(String s) {
            System.out.println("eval");
            return super.eval(s);
        }

        @Override
        public Object getMember(String name) {
            System.out.println("getMember " + name);
            return name.equals("length") ? arrayValues.size() : arrayValues.get(Integer.valueOf(name));
        }

        @Override
        public Object getSlot(int index) {
            //System.out.println("getSlot");
            return arrayValues.get(index);
        }

        @Override
        public boolean hasMember(String name) {
            System.out.println("hasMember");
            return super.hasMember(name);
        }

        @Override
        public boolean hasSlot(int slot) {
            System.out.println("hasSlot");
            return super.hasSlot(slot);
        }

        @Override
        public void removeMember(String name) {
            System.out.println("removeMember");
            super.removeMember(name);
        }

        @Override
        public void setMember(String name, Object value) {
            System.out.println("setMember");
            super.setMember(name, value);
        }

        @Override
        public void setSlot(int index, Object value) {
            System.out.println("setSlot");
            super.setSlot(index, value);
        }

        @Override
        public Set<String> keySet() {
            System.out.println("keySet");
            return arrayValues.keySet().stream().map(k -> "" + k).collect(Collectors.toSet());
        }

        @Override
        public Collection<Object> values() {
            System.out.println("values");
            return arrayValues.values();
        }

        @Override
        public boolean isInstance(Object instance) {
            System.out.println("isInstance");
            return super.isInstance(instance);
        }

        @Override
        public boolean isInstanceOf(Object clazz) {
            System.out.println("isINstanceOf");
            return super.isInstanceOf(clazz);
        }

        @Override
        public String getClassName() {
            System.out.println("getClassName");
            return super.getClassName();
        }

        @Override
        public boolean isFunction() {
            return false;
        }

        @Override
        public boolean isStrictFunction() {
            return false;
        }

        @Override
        public double toNumber() {
            return super.toNumber();
        }

        @Override
        public boolean isArray() {
            return true;
        }

        @Override
        public String toString() {
            return arrayValues.values().toString();
        }
    }

您的
Arrays.asList()
调用似乎使用
int[]
类型的单个元素创建了一个列表,而不是您想要的。请尝试
Arrays.asList(1,2,3,4)
相反。啊,谢谢:)这确实让事情变得更好了。我将更新这个问题。这里的主要问题不是JS数组实际上不是Java意义上的数组吗?它们更像是带有
int
键的映射。我对JS知之甚少,无法对此发表评论,但要解决我的问题,我需要将数组转换为
NativeArray
static class FooList implements List {
        final ScriptObjectMirror wrapped;

        public FooList(ScriptObjectMirror wrapped) {
            this.wrapped = wrapped;
        }

        @Override
        public int size() {
            return engine.eval("get length of wrapped JS object");
        }

        ... and so on ...
    }