簡體   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