我有一个Java应用程序,它允许用户通过定义JavaScript函数在运行时操纵某些对象。我们目前正在使用Java 8中的Nashorn进行此操作,但我们希望迁移到Java 11。一旦我们使用了Java 11,我们将能够使用GraalVM提供此功能,但目前我们需要维护Java8 -> Java 11升级的兼容性。
在Java 11中,当我们使用Nashorn函数时,该函数的行为似乎有所不同,这取决于该函数是否命名,Java 8中的情况并非如此。
$ jjs -v
nashorn 11.0.6
Warning: The jjs tool is planned to be removed from a future JDK release
jjs> function foo() {}
jjs> function () {}
function () {}注意,第一个函数定义不返回任何内容。在Java 8中,即使在函数命名时,它也返回该函数:
$ jjs -v
nashorn 1.8.0_252
jjs> function foo() {}
function foo() {}我们当前调用这些脚本的方式是:
CompiledScript compiled = scriptEngine.compile(userProvidedScript);
Object evaled = compiled.eval(bindings);
scriptEngine.invokeMethod(evaled, "call", evaled, ... input parameters ...)好奇是否有人知道这件事的根本原因和任何好的解决办法?出于后台原因,我需要支持function(...)和function foo(...)。由于这是在我们的Java应用程序中完成的,因此我们可能会以某种方式包装用户提供的脚本,或者尝试从绑定中获取脚本(这看起来很容易出错,因为可以定义多个脚本,Java 8的行为将用于调用最后定义的脚本)。
发布于 2022-02-16 06:12:35
可能是由于纳什霍恩的匿名函数语句的自定义特性(实际上称为"函数声明")出现问题,也不小心也适用于实际命名的函数声明。因为在纳什霍恩的文档中没有描述过这一点,所以我想他们不想要这种行为,于是就把它处理掉了。
解决方案:
转换源代码,以便作为它的最后一步,它将产生由您上次命名的函数声明定义的函数对象。
考虑一下我的测试,看看这在OpenJDK 8和11中是可行的:
nashorn @ 1.8.0_302:
jjs> function bar() { foo(); }; function foo() { bar(); }
function foo() { bar(); }
jjs> function bar() { foo(); }; function foo() { bar(); }; foo
function foo() { bar(); }nashorn @ 11.0.6:
jjs> function bar() { foo(); }; function foo() { bar(); }
jjs> function bar() { foo(); }; function foo() { bar(); }; foo
function foo() { bar(); }为了弄清楚要使用什么名称,您应该能够解析JS并使用套餐处理它的AST。
树访问者/函数名累加器看起来可能如下所示:
private static class FuncDeclarationVisitor extends SimpleTreeVisitorES5_1<Void, Void> {
public String lastFunctionName = null;
@Override
public Void visitFunctionDeclaration(FunctionDeclarationTree node, Void param) {
// Anonymous function declaration ==> null
IdentifierTree functionName = node.getName();
lastFunctionName = functionName != null ? functionName.getName() : null;
return super.visitFunctionDeclaration(node, param);
}
}您可以调用它,就像:
CompilationUnitTree parsedTree; // Use Parser's parse method
FuncDeclarationVisitor visitor = new FuncDeclarationVisitor();
parsedTree.accept(visitor);
return visitor.lastFunctionName; // Null if the last function declaration was anonymous但我不认为有任何方法可以修改AST,然后将其发送到NashornScriptEngine的编译器,您可能需要向源文本本身添加一些内容()。
此外,您还可能希望访问者检测到其他类型的节点,这些节点不是函数声明,这样您就不会意外地转换脚本并打击可能产生的其他表达式(非函数)。
https://stackoverflow.com/questions/62500957
复制相似问题