簡體   English   中英

如何從Java中的String動態創建Groovy Closure

[英]How to dynamically create a Groovy Closure from a String in Java

我想知道如何在Java應用程序中在運行時創建Closure對象,其中Closure的內容未提前知道。 我找到了解決方案,但我懷疑它是最佳的。

背景:我編寫了一些解析域特定語言的Groovy代碼。 解析代碼是靜態編譯的,並包含在Java應用程序中。 在解析器實現中,我有類充當DSL的特定部分的委托。 使用以下模式調用這些類:

class DslDelegate {
  private Configuration configuration

  def section(@DelegatesTo(SectionDelegate) Closure cl) {
    cl.delegate = new SectionDelegate(configuration)
    cl.resolveStrategy = Closure.DELEGATE_FIRST
    cl()
  }
}

我希望直接從Java代碼中調用這樣的方法。 我能夠創建一個新的DslDelegate對象,然后調用section()方法。 但是我需要創建並傳遞一個參數,該參數是Closure一個實例。 我希望從String對象初始化內容。

我的解決方案:以下Java代碼(實用程序)正在運行,但我要求改進。 當然,這可以更清潔或更有效的方式完成嗎?

/**
 * Build a Groovy Closure dynamically
 *
 * @param strings
 *            an array of strings for the text of the Closure
 * @return a Groovy Closure comprising the specified text from {@code strings}
 * @throws IOException
 */
public Closure<?> buildClosure(String... strings) throws IOException {
    Closure<?> closure = null;

    // Create a method returning a closure
    StringBuilder sb = new StringBuilder("def closure() { { script -> ");
    sb.append(String.join("\n", strings));
    sb.append(" } }");

    // Create an anonymous class for the method
    GroovyClassLoader loader = new GroovyClassLoader();
    Class<?> groovyClass = loader.parseClass(sb.toString());

    try {
        // Create an instance of the class
        GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();

        // Invoke the object's method and thus obtain the closure
        closure = (Closure<?>) groovyObject.invokeMethod("closure", null);
    } catch (InstantiationException | IllegalAccessException e) {
        throw new RuntimeException(e);
    } finally {
        loader.close();
    }

    return closure;
}

您可以使用GroovyShell從字符串創建Closure

public Closure<?> buildClosure(String... strings) {
    String scriptText = "{ script -> " + String.join("\n", strings) + " }";
    return (Closure<?>) new GroovyShell().evaluate(scriptText);
}

感謝@hzpz,我已經完成了類似的任務,但我讓它變得更美觀,更易於使用。 在我的情況下,閉包可能接受任何參數,所以我把參數列表放在閉包s code. Let s code. Let在String中動態創建閉包,看起來像這樣:

script1 = 'out,a,b,c-> out.println "a=${a}; b=${b}; c=${c}"; return a+b+c;'

現在,在String類中創建新方法

String.metaClass.toClosure = {
   return (Closure) new GroovyShell().evaluate("{${delegate}}")
}

現在我可以從String或文件或其他任何東西調用閉包。

println script1.toClosure()(out,1,2,3)

要么

println (new File('/folder/script1.groovy')).getText('UTF-8').toClosure()(out,1,2,3)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM