Danny Gloudemans
Danny Gloudemans

Reputation: 2697

Groovy: Dynamic Method Invocation and their parameters

Yesterday I started with using Groovy and I found out the Dynamic Method Invocation function. This is a nice function to call methods dynamically based on their method name. And this is working fine for me. Now we would like to call these methods based on their name with different parameters. For example I have 2 mehods:

 def changeResponseWithParametersAandB(def response, String a, String b) { 
        response.result = args[0];
        return response;
 }

 def changeResponseWithParameterA(def response, String a) { 
        response.result = args[0];
        return response;
 }

I will loop trough a list with the method names, like:

for (int i = 0; i < methods.size(); i++) {
    DynamicMethods dynamicMethod = methods.get(i);
    methodName = dynamicMethod.getMethodName();

    changeFieldValues."$methodName"(response, <HOW_SHOULD_I_DO_THIS_PART>);
}

The only problem is that this won’t work for one of the two methods. I should use for the first method 2 parameters and for the second method 3 parameters. Is there a way to solve this issue in groovy? Or should I just use a map/array or something like that?

Thanks for you answer!

Upvotes: 1

Views: 4608

Answers (2)

dmahapatro
dmahapatro

Reputation: 50275

Something like below would suffice? Instead of having two methods you can have one method with the second argument optional. I tried to mimic the implementation by maps and lists. Shout out if you need more clarifications.

def changeResponseWithParametersAandB(def response, String a, String b = null) { 
    response.result = [first: a, second: b]
    return response
}

def methods = [ 'changeResponseWithParametersAandB' ]
def response = [:]
def args = [ [ 'string1' ], [ 'string1', 'string2' ] ]

args.each { arg ->
    methods.each { method ->
        def result = "$method"( response, *arg )
        assert arg.size() == 1 ? 
            result == [ result : [ first:'string1', second:null ] ] : 
            result == [ result : [ first:'string1', second:'string2' ] ]
    } 
}

return "Done testing"

Upvotes: 8

Will
Will

Reputation: 14549

You can pack the parameters in a list and use as Object[] to pass them. I find invokeMethod slightly cleaner, but it is a matter of taste:

def foo(number, string) { number + string }
def bar(number) { number * 2 }

def calls = [foo: [90, 'string'], bar: [150]].collect { method, params ->
  this.invokeMethod(method, params as Object[])
}

assert calls[0] == '90string'
assert calls[1] == 300

Upvotes: 3

Related Questions