Nashorn访问非静态Java方法

时间:2014-11-25 07:18:24

标签: 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();");

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

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

哪个将运行函数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 */
}

如何使用Nashorn引擎访问Java 1.8中的Functions类?如果用户使用Java 1.8,我的目标是为第一个代码段运行不同的代码,同时仍然允许1.7的用户使用该应用程序。

我没试过http://www.doublecloud.org/2014/04/java-8-new-features-nashorn-javascript-engine/https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/api.htmlHow to instantiate a Java class in JavaScript using Nashorn?。他们似乎都没有像Java 1.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

2 个答案:

答案 0 :(得分:2)

我能够重现。首先,Nashorn一般不会尝试使用Java对象(非静态或其他方式)。我已经在其他项目中使用过它,并且没有任何重大问题从Java 7中的Rhino转换到migration guide所涵盖的内容。但是,这里的问题似乎与with statement的使用有关,而{&#34;不推荐&#34;根据MDN,在ECMAScript 5.1的strict模式下甚至不允许使用。

与此同时,我发现a thread on the Nashorn-dev mailing list正在讨论类似案例。答复的相关部分是:

  

Nashorn只允许脚本对象(即JS创建的对象)   构造函数或JS对象文字表达式)作为范围表达式   &#34;与&#34;声明。任意对象。 。 。不能用作&#39;范围&#39;的表达   &#39;与&#39;

     

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

它不是最优雅的解决方案,但是,如果不使用JDK 9,我可以通过在Javascript中编写代理对象来实现with的预期用途。 >镜像Java类的public API:

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);
    }
}

Attila Szegedi指出非标准 Nashorn Object.bindProperties函数。虽然它不能用于除Nashorn引擎之外的任何东西,但确实消除了重新声明proxy对象内所有公共API的复杂性。使用此方法,第一个jse.eval(...)调用可以替换为:

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

答案 1 :(得分:0)

我决定使用我的应用程序编译并捆绑“旧”Rhino解释器,而不是使用Nashorn。

https://wiki.openjdk.java.net/display/Nashorn/Using+Rhino+JSR-223+engine+with+JDK8