简体   繁体   English

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

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

A typical JSR-223 script would begin with a series of surrogate imports like this (JavaScript+Nashorn chosen for example purposes): 典型的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));

I want to get rid of those surrogates by emulating an import-like functionality for scripts. 我想通过为脚本模拟类似于导入的功能来摆脱这些替代。 That means, I want to have global objects (like Foo , bar , Logger and sin in the example above) pre-created by my Java code. 这意味着,我想通过我的Java代码预先创建全局对象(如上例中的FoobarLoggersin )。 This should automatically make a common set of imports available for multiple scripts. 这将自动使一组通用的导入可用于多个脚本。

I have found two methods for doing that with Nashorn: 我发现使用Nashorn可以做到这一点的两种方法:

Method 1 : Generate a script prelude and eval() it before the main script. 方法1 :生成脚本前奏,并在主脚本之前生成eval() That would be literally the first half of the example code above. 从字面上看,这就是上面示例代码的前半部分。

Method 2 : Obtain class and method references from a ScriptEngine, cache them and use for subsequent script invocations: 方法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));");

Obviously, none of those methods would work for any other JSR-223 engine. 显然,这些方法都不适用于任何其他JSR-223引擎。 Is there a way to implement the same in a portable manner? 有没有办法以可移植的方式实现它?

I have no idea on how to solve the issue regarding the new operation (how to avoid the calls to Java.type()). 我不知道如何解决有关新操作的问题(如何避免调用Java.type())。

But when you compile your script, you can assign methods as lambdas: 但是,在编译脚本时,可以将方法分配为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 );

For the method void bar() (no arguments, no return value), you have to provide your own functional interface, as the java.util.function package does not have one for that kind of method. 对于方法void bar() (无参数,无返回值),您必须提供自己的函数接口,因为java.util.function包没有针对该方法的接口。

Unfortunately, this approach seems not to work for not-compiled scripts. 不幸的是,这种方法似乎不适用于未编译的脚本。 And it does not work for all types of lambdas (functional interfaces). 并且它不适用于所有类型的lambda(功能接口)。 I did some experiments, but could not find a pattern yet what works and what not. 我做了一些实验,但是找不到一种模式,什么有效,什么无效。 It is for sure that functional interfaces that define a method throwing a checked exception do not work this way. 可以肯定的是,定义方法引发检查异常的功能接口不能以这种方式工作。 Also if the functional interface is not public but a private inner interface. 同样,如果功能接口不是公共的,而是私有的内部接口。

It should be obvious that I omitted the otherwise necessary error handling and try-catch blocks from the sample code above. 很明显,我从上面的示例代码中省略了其他必要的错误处理和try-catch块。

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

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