Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy: Execute Code transparent before and after any method is invoked

Let's say we have a groovy class with some methods (static or not static). What i want to do is executing some code before and after every method of this class is invoked without touchung the class at all and without dynamically manipulating the code inside of each method.

What i tried using groovy metaClass; getting all methods of the metaClass and then dynamically replacing the every method with a wrapping method, containing some code and in the middle invoking the old method. Problem is, i don't know the parameters of each original method so i can't replace the old methods with new methods (closures) because i cannot create wrapping closures with varying numbers and types of parameters dynamically and even if yi could, i didn't know how to access them inside the wrapping closure. I need that the wrapping closure has the same signature of the old method so that the closure gets called when someone tries to call the old method after the class was transparently changed.

In Javascript e.g. i can use the args[] array to access all arguments in a function body even if i don't know the arguments names at the time when writing the code.

How can i do this in groovy? Or is their maybe another way to achieve what i try to do?

like image 731
valenterry Avatar asked Mar 20 '23 23:03

valenterry


1 Answers

Something like below will do? Using invokeMethod to intercept calls to each method. Test is self explanatory.

Explanation:

Below metaClass implementation overrides invokeMethod from GroovyObject. Since all groovy objects inherit from GroovyObject, we gain the flexibility of manipulating/intercepting method calls or even specify our own methodMissing implementation. We would need one override for static and one for non-static methods. Basically, invokeMethod intercepts calls to each method on the Class on which it is defined. We end up with some before and after functionalities for each method. Using reflection the below implementation is able to find out the method by its name and argument and invoke it in runtime.

Note:-

  • Make sure the returned value from the method call is returned from the closure as well
  • Might be a expensive of a class has number of methods with heavy implementation
  • If selective execution is required, then check for the method name and then intercept the call

Implementation:

class Dummy {
    def method1() { System.out.println "In method 1" }
    def method2(String str) { System.out.println "In method 2" }
    static def method3(int a, int b) { 
        System.out.println "In static method 3" 
    }    
}

Dummy.metaClass.invokeMethod = {String name, args ->
   def result

   System.out.println(
     "Do something before $name is called with args $args")

   try {
      result = delegate.metaClass.getMetaMethod(name, args)
                                 .invoke(delegate, args)
   } catch(Exception e) {
       System.out.println "Handling exception for method $name"
   }

   System.out.println(
      "Do something after $name was called with args $args \n")

   result
}

Dummy.metaClass.'static'.invokeMethod = {String name, args ->
   def result

   System.out.println(
     "Do something before static method $name is called with args $args")

   try {
      result = delegate.metaClass.getMetaMethod(name, args)
                                 .invoke(delegate, args)
   } catch(Exception e) {
       System.out.println "Handling exception for method $name"
   }

   System.out.println(
     "Do something after static method $name was called with args $args \n")

   result
}

def dummy = new Dummy()
dummy.method1()
dummy.method2('Test')
Dummy.method3(1, 2)
like image 76
dmahapatro Avatar answered Apr 06 '23 19:04

dmahapatro