【问题标题】:How to dynamically create a Groovy Closure from a String in Java如何从 Java 中的字符串动态创建 Groovy 闭包
【发布时间】:2016-04-21 13:43:19
【问题描述】:

我想知道如何在运行时从 Java 应用程序中创建一个 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;
}

【问题讨论】:

  • 好问题。你有没有找到更清洁的解决方案?

标签: java groovy closures


【解决方案1】:

您可以使用GroovyShell 从字符串创建Closure

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

【讨论】:

    【解决方案2】:

    感谢@hzpz,我完成了类似的任务,但我让它变得更漂亮、更易于使用。在我的情况下,闭包可能接受任何参数,所以我将参数列表放在closures code. Lets 中说闭包在字符串中动态创建,如下所示:

    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}}")
    }
    

    现在我可以从字符串或文件或其他任何东西调用闭包。

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

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

    【讨论】:

      猜你喜欢
      • 2012-07-14
      • 1970-01-01
      • 1970-01-01
      • 2015-02-18
      • 2017-03-21
      • 1970-01-01
      • 1970-01-01
      • 2013-10-29
      • 1970-01-01
      相关资源
      最近更新 更多