[英]Compiled Groovy Scripts
據我了解,至少有2種方法可以用Java編譯Groovy腳本。
使用javax.script.ScriptEngine轉換為CompiledScript 。
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Groovy"); Bindings bindings = new SimpleBindings(); bindings.put("foo", 1234); Compilable compEngine = (Compilable)engine; CompiledScript cs = compEngine.compile("if (foo == 1234) true else false"); cs.eval(bindings);
使用GroovyClassLoader#parse
,做一些中間工作,然后調用GroovyObject#invokeMethod(String, Object[])
。
注意-以下代碼來自Groovy in Action 。 我發現這是一本學習Groovy的好書。
GroovyClassLoader gcl = new GroovyClassLoader();
// Note, assume that the Groovy script gets compiled to a class that
// includes a method, "do". And "do" accepts an `Integer` argument, "foo."
Class foo = gcl.parseClass("if (foo == 1234) true else false");
GroovyObject hello = (GroovyObject) foo.newInstance();
Object[] args = { Integer.valueOf(1234) };
assert true == (foo.invokeMethod("do", args));
據我了解這兩種方法之間的差異,第一個方法涉及用key-value
對(變量名到值)填充Bindings
映射。 然后,我們通過CompiledScript#eval(Bindings)
執行CompiledScript
,其中Bindings
參數會發生突變。
但是,假設我想將Foo
類對象傳遞給方法Foo#do
。 並且,而不是評估if (foo == 1234) ...
,我需要在源代碼中編寫:
if(fooObj.getFoo() == 1234) ...
然后,結果發現我需要對DSL進行后處理 ,以包括獲取foo
的正確方法。
總的來說,根據我上面的示例,有沒有更簡單的方法可以實現第二種方法?
實際上有2個以上的選項。 所有文檔均在文檔中進行了描述(請參閱http://docs.groovy-lang.org/2.3.8/html/documentation/#_integrating_groovy_in_a_java_application ),但是無論如何,我都不會使用JSR-223(javax (.script),因為它是一個非常差的集成機制。
例如,使用GroovyShell
或GroovyClassLoader
,您可以設置自己的基本腳本類,這將使您非常輕松地設置foo
實例,但是您也可以從基本腳本類中調用任何方法。
順便說一句,所有的Groovy腳本將實施的方法不do
,但run
。 因此,假設您具有以下基類:
public abstract class MyDSL extends groovy.lang.Script {
Object fooObj
public void setFooObj(Object foo) { fooObj = foo; }
public Object getFooObj() { return fooObj; }
}
和Foo
的Holder類是這樣的:
public class FooHolder {
def getFoo() { return 1234; }
}
那么您可以通過以下方式創建腳本:
CompilerConfiguration config = new CompilerConfiguration();
config.setScriptBaseClass("test.MyDSL");
GroovyClassLoader gcl = new GroovyClassLoader(this.getClass().getClassLoader(),config);
Class<? extends MyDSL> scriptClass = gcl.parseClass("return (fooObj.getFoo()==1234)");
MyDSL v1 = scriptClass.newInstance();
v1.setFooObj(new FooHolder());
Object result = v1.run();
請注意,這實際上是執行此操作的一種方法,但不一定是您需要的最佳方法。 也許您可以描述更多您想要實現的目標,但是Groovy有很多選擇,從像這樣的腳本到擴展自己的類或接口的類。 看一下文檔,讓我們知道。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.