Nashorn访问非静态Java方法

Nashorn访问非静态Java方法,java,javascript,nashorn,Java,Javascript,Nashorn,在Java 7(1.7)中,我可以通过运行以下命令从JavaScript访问Java方法: ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript"); jse.eval("importClass(net.apocalypselabs.symat.Functions);"); jse.eval("SyMAT_Functions = new net.apocalypselabs.symat.Functions

在Java 7(1.7)中,我可以通过运行以下命令从JavaScript访问Java方法:

ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
jse.eval("importClass(net.apocalypselabs.symat.Functions);");
jse.eval("SyMAT_Functions = new net.apocalypselabs.symat.Functions();");

String input = "notify(\"Foo\");"; // This is user input

jse.eval("with(SyMAT_Functions){ "+input+" }");
它将从Functions java类运行notify()函数:

public class Functions {
    private Object someObjectThatCannotBeStatic;
    public void notify(Object message) {
        JOptionPane.showMessageDialog(null, message.toString());
    }
    /* Lots more functions in here, several working with the same non-static variable */
}
package com.example;

import javax.script.*;

public class StackOverflow27120811
{
    public static void main(String... args) throws Exception {
        ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
        jse.eval(
            "var real = new Packages.com.example.StackOverflow27120811(); " +
            "var proxy = { doSomething: function(str) { return real.doSomething(str); } }; "
        );
        jse.eval("with (proxy) { doSomething(\"hello, world\"); } ");
    }

    public void doSomething(String foo) {
        System.out.println(foo);
    }
}
如何使用Nashorn引擎访问Java1.8中的Functions类?我的目标是,如果用户拥有Java1.8,则为第一个代码段运行不同的代码,同时仍然允许拥有1.7的用户使用该应用程序

我试过,但运气不好。它们似乎都不允许我做与Java1.7相同的事情,而是假设我只想访问静态函数和对象

我遇到的最常见错误是:

我从

ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
jse.eval("var SyMAT_Functions;with (new JavaImporter(Packages.net.apocalypselabs.symat)) {"
                    + "SyMAT_Functions = new Functions();}");
……然后

jse.eval("with(SyMAT_Functions){ "+input+" }");
…吐出

TypeError: Cannot apply "with" to non script object in <eval> at line number 1
TypeError:无法将“with”应用于第1行中的非脚本对象

我能够复制。首先,Nashorn并没有试图让Java对象(非静态或其他)在一般情况下难以使用。我曾在其他项目中使用过它,在Java7中从Rhino转换到Rhino时没有遇到任何重大问题。然而,根据MDN,这里的问题似乎涉及“不推荐”的使用,甚至在ECMAScript 5.1的
strict
模式中不允许使用

同时,我发现我在讨论一个类似的案例。答复的相关部分是:

Nashorn只允许脚本对象(即由JS创建的对象 构造函数或JS对象文字表达式)作为的范围表达式 “with”语句。任意对象。不能用作的“范围”表达式 “有”

在jdk9中,添加了对脚本对象和其他镜像对象的支持 脚本引擎或其他全局对象(ScriptObjectMirror的实例)

这不是最优雅的解决方案,但在不使用JDK 9的情况下,我能够通过在Javascript中编写代理对象来镜像Java类的
public
API,从而实现您对
with
的预期用途:

public class Functions {
    private Object someObjectThatCannotBeStatic;
    public void notify(Object message) {
        JOptionPane.showMessageDialog(null, message.toString());
    }
    /* Lots more functions in here, several working with the same non-static variable */
}
package com.example;

import javax.script.*;

public class StackOverflow27120811
{
    public static void main(String... args) throws Exception {
        ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
        jse.eval(
            "var real = new Packages.com.example.StackOverflow27120811(); " +
            "var proxy = { doSomething: function(str) { return real.doSomething(str); } }; "
        );
        jse.eval("with (proxy) { doSomething(\"hello, world\"); } ");
    }

    public void doSomething(String foo) {
        System.out.println(foo);
    }
}

指出了非标准Nashorn函数。虽然它不能与Nashorn引擎一起工作,但它确实消除了在
代理
对象中重新声明所有公共API的复杂性。使用这种方法,第一个
jse.eval(…)
调用可以替换为:

jse.eval(
    "var real = new Packages.com.example.StackOverflow27120811(); " +
    "var proxy = { }; " +
    "Object.bindProperties(proxy, real); " // Nashorn-only feature
);

我决定编译“旧”Rhino解释器并将其与我的应用程序捆绑在一起,而不是使用Nashorn


什么在Java 8中不起作用?是否可以包含错误消息或堆栈跟踪?@WilliamPrice根据我尝试使用的方法,错误会发生变化。我的问题是,无论我怎么努力,我都无法访问Java 8中的非静态方法。@WilliamPrice好的,我已经编辑了一次尝试,以及它得到了什么。我已经尝试了这些链接中给出的所有不同方法,如果我没记错的话,它们在修补后都给了我
TypeError
。Nashorn还公开了名为
bindProperties
对象
构造函数上的非标准函数。这样,您可以将一个对象的所有属性作为绑定属性添加到另一个对象;这基本上提供了您所做的那种自动代理(您也可以通过绑定多个对象的属性来创建复合,但我离题了)。您可以使用
var proxy=Object.bindProperties({},real)在上面的示例中。我知道,如果我们用声明进行扩展,这样它就可以接受POJO,那就更好了……这不是一个严格的技术限制,只是一些我们目前还无法开发的东西。