为什么我不能 运行 数据库中的 JS?
Why can't I run the JS that is in the database?
我需要运行一个以字符串格式保存在mongoDB中的JS命令。为什么不运行数据大写?
Java
public String read(String chave, String valor){
String processador = atributoDAO.getProcessador(chave);
if(processador != null){
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
try {
engine.eval(processador);
Invocable invocable = (Invocable)engine;
valor = (String)invocable.invokeFunction("process", valor);
} catch (ScriptException e) {
Log.error(AtributoReader.class, "erro no engine js", e);
} catch (NoSuchMethodException e) {
Log.error(AtributoReader.class, "erro no engine js", e);
}
return valor;
}
return valor;
}
数据库
{
"_id" : ObjectId("55390277e230ebff4fe25755"),
"atributo" : "peca_nome",
"processador" : "function(val) { return val.toUpperCase(); }"
}
当您执行 engine.eval("function(val) { return val.toUpperCase(); }")
时,您会在脚本引擎的范围内创建一个匿名函数。不幸的是,以后无法调用它,因为该函数未分配给变量。
您的调用 invocable.invokeFunction("process", valor);
试图调用 function process( val )
,但您的脚本引擎上下文中不存在具有该名称的函数。所以它抛出一个 NoSuchMethodException
.
对此有两种可能的解决方案。
要么重写数据库中的代码片段,将函数分配给一个变量,以便稍后调用它:
{
"_id" : ObjectId("55390277e230ebff4fe25755"),
"atributo" : "peca_nome",
"processador" : "process = function(val) { return val.toUpperCase(); };"
}
或者,在编译脚本之前,使用 Java 将变量添加到 Java 脚本源代码:
engine.eval("process = " + processador);
顺便说一下: 在数据库中存储可执行代码通常是一个非常危险的安全想法。当有任何方法可以将用户提供的数据放入这些代码片段中时,您就会向危险的代码执行漏洞开放您的应用程序。默认情况下,nashorn 脚本引擎根本没有沙盒化,而且非常强大。它可以做任何 JavaVM 可以做的事情,包括从您的项目和 java 标准库中调用任何方法或构造任何对象。你在这里做的事情看起来好像你要玩弄装满子弹的枪。 如果您知道自己在做什么并且如果您遵守所有安全预防措施,它可能是安全的,但是看起来你正要向自己(或其他人)开枪。
您可以评估一个匿名函数并将结果存储为一个对象。生成的对象是 ScriptObjectMirror (https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/ScriptObjectMirror.html) which has a method to call (https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/ScriptObjectMirror.html#call-java.lang.Object-java.lang.Object...-) 类型的函数。
代码如下
Object thiz = engine.eval("this"); // get you global object
ScriptObjectMirror func = engine.eval("function() { print('hello'); }");
func.call(thiz); // pass global object as "this" for the function
我需要运行一个以字符串格式保存在mongoDB中的JS命令。为什么不运行数据大写?
Java
public String read(String chave, String valor){
String processador = atributoDAO.getProcessador(chave);
if(processador != null){
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
try {
engine.eval(processador);
Invocable invocable = (Invocable)engine;
valor = (String)invocable.invokeFunction("process", valor);
} catch (ScriptException e) {
Log.error(AtributoReader.class, "erro no engine js", e);
} catch (NoSuchMethodException e) {
Log.error(AtributoReader.class, "erro no engine js", e);
}
return valor;
}
return valor;
}
数据库
{
"_id" : ObjectId("55390277e230ebff4fe25755"),
"atributo" : "peca_nome",
"processador" : "function(val) { return val.toUpperCase(); }"
}
当您执行 engine.eval("function(val) { return val.toUpperCase(); }")
时,您会在脚本引擎的范围内创建一个匿名函数。不幸的是,以后无法调用它,因为该函数未分配给变量。
您的调用 invocable.invokeFunction("process", valor);
试图调用 function process( val )
,但您的脚本引擎上下文中不存在具有该名称的函数。所以它抛出一个 NoSuchMethodException
.
对此有两种可能的解决方案。
要么重写数据库中的代码片段,将函数分配给一个变量,以便稍后调用它:
{
"_id" : ObjectId("55390277e230ebff4fe25755"),
"atributo" : "peca_nome",
"processador" : "process = function(val) { return val.toUpperCase(); };"
}
或者,在编译脚本之前,使用 Java 将变量添加到 Java 脚本源代码:
engine.eval("process = " + processador);
顺便说一下: 在数据库中存储可执行代码通常是一个非常危险的安全想法。当有任何方法可以将用户提供的数据放入这些代码片段中时,您就会向危险的代码执行漏洞开放您的应用程序。默认情况下,nashorn 脚本引擎根本没有沙盒化,而且非常强大。它可以做任何 JavaVM 可以做的事情,包括从您的项目和 java 标准库中调用任何方法或构造任何对象。你在这里做的事情看起来好像你要玩弄装满子弹的枪。 如果您知道自己在做什么并且如果您遵守所有安全预防措施,它可能是安全的,但是看起来你正要向自己(或其他人)开枪。
您可以评估一个匿名函数并将结果存储为一个对象。生成的对象是 ScriptObjectMirror (https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/ScriptObjectMirror.html) which has a method to call (https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/ScriptObjectMirror.html#call-java.lang.Object-java.lang.Object...-) 类型的函数。
代码如下
Object thiz = engine.eval("this"); // get you global object
ScriptObjectMirror func = engine.eval("function() { print('hello'); }");
func.call(thiz); // pass global object as "this" for the function