【问题标题】:groovy evaluate string as the function which exists in the same scriptgroovy 将字符串评估为存在于同一脚本中的函数
【发布时间】:2019-12-21 16:54:06
【问题描述】:

我正在尝试将字符串评估为 groovy 中的代码,即使方法存在于同一个脚本中,它也会因 groovy.lang.MissingMethodException 异常而失败。据我了解,groovy 每次尝试评估代码时都会运行新实例,但是有没有办法将当前脚本注入Eval.meGroovyShell().evaluate() 以便它可以找到方法并运行它? 下面是示例代码sn-p,

def justSayHello(){
    return "hello"
}

def my_str = "justSayHello()"
//Eval.me(my_func_str)
new GroovyShell().evaluate(my_func_str) 

EvalGroovyShell().evaluate() 都在抛出异常

Caught: groovy.lang.MissingMethodException: No signature of method: Script1.justSayHello() is applicable for argument types: () values: []
groovy.lang.MissingMethodException: No signature of method: Script1.justSayHello() is applicable for argument types: () values: []
        at Script1.run(Script1.groovy:1)
        at string_split.run(string_split.groovy:35)

【问题讨论】:

    标签: groovy eval evaluate


    【解决方案1】:

    以下代码:

    justSayHello = {
      println "hello"
    }
    
    def my_str = "justSayHello()"
    
    new GroovyShell(binding).evaluate(my_str) 
    

    运行时打印出hello。在这里,我们将 justSayHello 从一个方法(在一个您看不到但 groovy 编译器围绕您的脚本生成的隐式类上)更改为一个闭包。此外,我们没有做def justSayHello,因为这会将它定义为隐式周围类上的一个字段(同样你看不到,但它就在那里),而只是定义没有任何修饰符的变量,将其放入脚本的全局绑定。

    然后我们将绑定发送到 GroovyShell,以便它可以找到变量。

    结果:

    ─➤ groovy solution.groovy
    hello
    

    一个更通用的变体是做这样的事情:

    def justSayHello() {
      println "hello"
    }
    
    def someOtherMethod() {
      println "hello again"
    }
    
    def methods = this.class.declaredMethods.findResults { m -> 
      if (m.name.startsWith('$') || m.name in ['main', 'run']) return null
      [m.name, this.&"${m.name}"]
    }.collectEntries { it }
    
    // just for debugging, print the methods
    methods.each { k, v -> 
      println "method: $k"
    }
    
    def my_str = "justSayHello()"
    new GroovyShell(new Binding(methods)).evaluate(my_str) 
    

    打印:

    ─➤ groovy solution.groovy
    
    method: justSayHello
    method: someOtherMethod
    hello
    

    这里我们找到所有由groovy生成的隐式类中声明的方法,删除一些由groovy编译器添加的东西(即mainrun和以$开头的方法),然后发送结果映射作为 GroovyShell 构造函数的绑定。

    我怀疑可能有更优雅的方式来实现这一点,所以任何 groovy 大师 - 随时在这里纠正我。

    有关 groovy 脚本的隐式封闭类的说明,请参见例如 this stackoverflow answer

    【讨论】:

    • 谢谢@Matias,将方法修改为闭包确实有效,但问题是我的实时场景方法未在当前类中定义,而是从不同的类中导入。所以我无法控制它来修改它。
    • 您仍然可以使用第二种方法并在定义该方法的类中枚举已声明的类。除了将 this.class.delclaredMethods 替换为 YourOtherClass.declaredMethods 之外,应该完全相同
    猜你喜欢
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多