5

I have an instance of a java object, let's say an instance of ArrayList called myList.

For this particular instance, I want to override the invokeMethod method to (say) log that method was called.

I could do something like this:

myList.metaclass.invokeMethod { name, args -> 

   println "Called ${name} with ${args}"
   whatGoesHere.invokeMethod(name, args)

}

Notice the 2nd line of the closure - how can I call the original invokeMethod method? Am I going about this correctly?

Roy Truelove
  • 22,016
  • 18
  • 111
  • 153

1 Answers1

6

There might be a shorter route to the original method, but this should work:

def myList = [ 1, 2, 3 ]

myList.metaClass.invokeMethod { name, args -> 
   println "Called ${name} with ${args}"
   delegate.class.metaClass.getMetaMethod( name, args )?.invoke( delegate, args )
}

myList.sum()
tim_yates
  • 167,322
  • 27
  • 342
  • 338
  • I found that this failed in the case of varargs functions where the method was being passed an ArrayList. The `args` would be of type Object[] with ArrayList as an element... so it matches successfully with the `getMetaMethod`. I believe the problem is that it fails to coerce the ArrayList in to an Object[], so it fails with `IllegalArgumentException: argument type mismatch`. In my case, the workaround was to switch some types from ArrayList to Object[] and it worked correctly. It would be some work to figure out what the proper `invokeMethod` fix would be. – brunobowden Jun 30 '15 at 06:00
  • More extensive answer to this for handling varargs: http://stackoverflow.com/a/31143363/1509221 – brunobowden Jul 02 '15 at 01:36
  • Is there a way to really call the original invokeMethod function? If some other code has already modified the invokeMethod in the metaclass to do something, if you use the above technique you will overwrite their invokeMethod. – burns Jun 02 '18 at 06:07