Java ScriptEngine:如何在Java端使用值?

7
在Java程序中,我正在调用一个用户定义的JavaScript程序:
File userJSFile=...;
javax.script.ScriptEngineManager mgr=new  ScriptEngineManager();
javax.script.ScriptEngine scripEngine= mgr.getEngineByExtension("js");
Object result=scripEngine.eval(new java.io.FileReader(userJSFile));

现在我想使用“result”:我如何访问它?我可以将其识别为数组(可以遍历其成员)、StringInteger等吗?谢谢。 编辑: 我只知道我的用户给了我一个返回最后一个值的脚本。我不知道这个值是一个String、数组等等。但我想使用它。
3个回答

9

除非是简单值,否则我更愿意让脚本引擎将其值强制转换为Java类型。

public class ScriptDemo {

  static class Result {
    private String[] words;

    public void setWords(String[] words) {
      this.words = words;
    }
  }

  static final String SCRIPT = "var foo = 'Hello World!';\n"
      + "result.setWords(foo.split(' '));";

  public static void main(String[] args)
      throws ScriptException {
    Result result = new Result();
    javax.script.ScriptEngineManager mgr = new ScriptEngineManager();
    javax.script.ScriptEngine scripEngine = mgr
        .getEngineByExtension("js");
    scripEngine.getContext().setAttribute("result", result,
        ScriptContext.ENGINE_SCOPE);
    scripEngine.eval(SCRIPT);
    System.out.println(Arrays.toString(result.words));
  }

}

即使你不能编辑脚本,你也可以拿到返回值并将其传递到您自己生成的脚本中进行强制转换。这假设您对返回的值有所了解。

编辑:由于没有关于返回值的任何信息,我会先使用Java(getClass())进行测试,以查看它是否是java.lang类型之一。如果返回的对象来自库的某些API私有部分,我将使用脚本语言(在这种情况下为JavaScript)对其进行内省,可能在过程中将其强制转换为Java类型或将其属性推入某些Java数据结构。

我的JavaScript有点生疏,但John Leach的教程看起来非常不错:JavaScript Introspection

(您可能可以使用Java反射,但由于引擎实现可能因Java版本/JRE/JavaScript引擎而异,因此我不会依赖它。)


2
这个问题很久以前就被问过了,但是答案看起来仍然正确。如果有其他人试图在Java和Javascript之间传递复杂对象,我想提供我的解决方案。
我编写了一个脚本,将NativeObject转换为(内存中的)JSON对象(实际上我使用MongoDB的基于BSON的对象,但是您应该只需在下面的示例代码中一对一地替换JSONArray和JSONObject即可)。
因此,例如,假设我有一个(用户)脚本“create_object_script”,它“返回”一些感兴趣的对象或数组,那么我可以将其转换为JSON(即哈希映射列表),如下所示:
Object returnVal = engine.eval(create_object_script);
engine.put("output", returnVal);
BasicDBObject objFactory = new BasicDBObject(); // (or JSON equivalent)
BasicDBList listFactory = new BasicDBList(); // (or JSON equivalent)
BasicDBList outList = new BasicDBList(); // (or JSON equivalent)
engine.put("objFactory", objFactory);
engine.put("listFactory", listFactory);
engine.put("outList", outList);
engine.eval(parsing_script); // (described below)
// "outList" is now populated with (in-memory) JSON representations of "returnVal"

显然,如果您对“create_object_script”脚本有控制权,您可以在一步完成此操作;我的脚本是用户生成的,因此隐藏这种复杂性是必要的-用户只需编写脚本,“返回值”是最后一行。
我将“parsing_script”放在这里,以保持本帖子的长度。
从功能上讲,这非常好用;我在JS中没有进行过开发,因此可能有更有效的方法来实现此目的。(请注意,我始终需要列表中的结果,如果您不需要,则可以传递BasicDBObject“outObj”,并在单例情况下写入该对象)。
希望这能帮助到昨晚1点处于我的状况的某个人!

0

这个链接可能会有所帮助。看起来最好的方法是依赖于特定实现的类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接