问题
I have a global shared library on Jenkins implicitly loaded on all pipelines, then my Jenkinsfile
is like that:
new com.company.Pipeline()()
And then the shared library has on directory src/com/company
some files, below the Pipeline.groovy
class:
package com.company
import static Utils.*
def call() {
// some stuff here...
}
The problem is, this way I have to static declare all methods, thus I lose the context and cannot access jenkins' methods easly without the Pipeline
class' instance. As you can see here they passing this
to the method mvn
.
Thinking of avoid this I was wondering about dynamically add all methods as closures by calling Utils.install this
instead of using import static Utils.*
, then my Utils.groovy
is something like that:
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.
}
But it raises an GStringImpl
cannot be cast to String
error, I believe .&
do not work with variables, how can I convert a method into closure having the method name on a variable? I have the MetaMethod mostly being a CachedMethod instance, if it were possible to turn it a ClosureMetaMethod instance maybe the problem can be solved, but whenever I search for method to closure conversion for groovy I just found the .&
solution!
If I use instance.metaClass.someMethod = utils.&someMethod
it do work, but I want it to be dinamic as I add new methods without needing to worry about sharing it.
回答1:
There is a way to do it dynamically. Notation utils.&someMethod
returns a MethodClosure object that can be simply instantiated with its constructor:
MethodClosure(Object owner, String method)
Consider following example:
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!"
In this example I use def closure = new MethodClosure(utils, method)
to get object method reference and then add this method to instance
object. I hope it helps.
来源:https://stackoverflow.com/questions/45600613/how-to-dynamically-add-all-methods-of-a-class-into-another-class