繁体   English   中英

如何将类型和函数传递给JSR-223脚本?

[英]How to pass types and functions to a JSR-223 script?

典型的JSR-223脚本将以如下所示的一系列替代导入(出于示例目的选择JavaScript + Nashorn)开始:

// "import" classes and static methods
var Foo = Java.type("my.package.Foo"); // application classes require Java.type() use
var bar = Foo.bar; // static method
var Logger = java.util.logging.Logger; // system classes can be accessed directly
var sin = java.lang.Math.sin; // the same for static methods

// use them
var foo = new Foo();
print(bar());
var log = Logger.getLogger("foo");
print(sin(42));

我想通过为脚本模拟类似于导入的功能来摆脱这些替代。 这意味着,我想通过我的Java代码预先创建全局对象(如上例中的FoobarLoggersin )。 这将自动使一组通用的导入可用于多个脚本。

我发现使用Nashorn可以做到这一点的两种方法:

方法1 :生成脚本前奏,并在主脚本之前生成eval() 从字面上看,这就是上面示例代码的前半部分。

方法2 :从ScriptEngine获取类和方法引用,对其进行缓存并用于后续的脚本调用:

ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine nashorn = sem.getEngineByName("nashorn");

Object fooClass = nashorn.eval("Java.type('my.package.Foo')"); // instance of jdk.internal.dynalink.beans.StaticClass
Object loggerClass = nashorn.eval("java.util.logging.Logger"); // the same

Object barFunction = nashorn.eval("Java.type('my.package.Foo').bar"); // instance of jdk.internal.dynalink.beans.SimpleDynamicMethod
Object sinFunction = nashorn.eval("java.lang.Math.sin"); // the same

ScriptEngine nashorn1 = sem.getEngineByName("nashorn");

nashorn1.put("Foo", fooClass);
nashorn1.put("bar", barFunction);
nashorn1.put("Logger", loggerClass);
nashorn1.put("sin", sinFunction);
nashorn1.eval("var foo = new Foo(); bar(); var log = Logger.getLogger('foo'); print(sin(42));");

显然,这些方法都不适用于任何其他JSR-223引擎。 有没有办法以可移植的方式实现它?

我不知道如何解决有关新操作的问题(如何避免调用Java.type())。

但是,在编译脚本时,可以将方法分配为lambda:

ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
Compilable nashorn = (Compilable) scriptEngineManager.getEngineByName( "Nashorn" );

CompiledScript script = nashorn.compile( "print( sin( 3.14 ) ); var log = getLogger( 'foo' );" );

Bindings bindings = new SimpleBindings();
bindings.put( "sin", (DoubleFunction<Double>) Math::sin );
bindings.put( "getLogger", (Function<String,Logger>) Logger::getLogger );

script.eval( bindings );

对于方法void bar() (无参数,无返回值),您必须提供自己的函数接口,因为java.util.function包没有针对该方法的接口。

不幸的是,这种方法似乎不适用于未编译的脚本。 并且它不适用于所有类型的lambda(功能接口)。 我做了一些实验,但是找不到一种模式,什么有效,什么无效。 可以肯定的是,定义方法引发检查异常的功能接口不能以这种方式工作。 同样,如果功能接口不是公共的,而是私有的内部接口。

很明显,我从上面的示例代码中省略了其他必要的错误处理和try-catch块。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM