【问题标题】:How to dynamically add all methods of a class into another class如何将一个类的所有方法动态添加到另一个类中
【发布时间】:2023-03-03 20:09:01
【问题描述】:

我在所有管道上隐式加载了一个global shared library on Jenkins,然后我的Jenkinsfile 是这样的:

new com.company.Pipeline()()

然后共享库在目录src/com/company 上有一些文件,在Pipeline.groovy 类下面:

package com.company  

import static Utils.*

def call() {
  // some stuff here...
}

问题是,这样我必须静态声明所有方法,因此我失去了上下文并且没有Pipeline类的实例就无法轻松访问jenkins的方法。如您所见here 他们将this 传递给方法mvn

考虑避免这种情况我想知道通过调用Utils.install this而不是使用import static Utils.*来动态添加所有方法作为闭包,然后我的Utils.groovy是这样的:

package com.company

private Utils() {}

static def install(def instance) {
  def utils = new Utils()
  // Some extra check needed here I know, but it is not the problem now
  for (def method in (utils.metaClass.methods*.name as Set) - (instance.metaClass.methods*.name as Set)) {
    def closure = utils.&"$method"
    closure.delegate = instance
    instance.metaClass."$method" = closure
  }
}

def someMethod() {
  // here I want to use sh(), tool(), and other stuff freely.
}

但它会引发 GStringImpl cannot be cast to String 错误,我相信 .& 不适用于变量,如何将方法转换为在变量上具有方法名称的闭包?我的MetaMethod 主要是CachedMethod 实例,如果可以将其转换为ClosureMetaMethod 实例,也许问题可以解决,但是每当我搜索groovy 的闭包转换方法时,我就找到了@987654344 @解决方案!

如果我使用instance.metaClass.someMethod = utils.&someMethod,它确实可以工作,但我希望它是动态的,因为我添加了新方法而无需担心共享它。

【问题讨论】:

    标签: jenkins reflection groovy jenkins-pipeline


    【解决方案1】:

    有一种方法可以动态进行。表示法utils.&someMethod 返回一个MethodClosure 对象,可以简单地用它的构造函数进行实例化:

    MethodClosure(Object owner, String method)
    

    考虑以下示例:

    class Utils {
        def foo() {
            println "Hello, Foo!"
        }
        def bar() {
            println "Hello, Bar!"
        }
    }
    
    class Consumer {
    }
    
    def instance = new Consumer()
    def utils = new Utils()
    
    (utils.metaClass.methods*.name - instance.metaClass.methods*.name).each { method ->
        def closure = new MethodClosure(utils, method)
        closure.delegate = instance
        instance.metaClass."$method" = closure
    }
    
    instance.foo() // Prints "Hello, Foo!"
    instance.bar() // Prints "Hello, Bar!"
    

    在本例中,我使用def closure = new MethodClosure(utils, method) 获取对象方法引用,然后将此方法添加到instance 对象。希望对你有帮助。

    【讨论】:

    • 完美,它起作用了,只是为了注册我没有使用每个因为詹金斯抱怨它不可序列化,但解决了问题,谢谢。
    • @TiagoPimenta 很酷,很高兴能帮到你:)
    猜你喜欢
    • 1970-01-01
    • 2013-02-10
    • 2012-02-17
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 2020-02-26
    • 1970-01-01
    • 2022-12-10
    相关资源
    最近更新 更多