Metaobject Protocol & Interceptors In Grails

Posted By : Jasgeet Singh | 27-Jul-2014

 

Metaobject Protocol

Metaprogramming means writing programs that manipulate programs. In Groovy, we can use MOP to invoke methods dynamically and synthesize classes and methods on the fly. This can give us the feeling that our object favorably changed its class. Groovy allows metaprogramming for POJOs and POGOs.

 

Intercepting Methods Using GroovyInterceptable

If Groovy object implements GroovyInterceptable, then its invokeMethod() is called when any of its methods are called—both existing methods and nonexistent methods. That is, GroovyInterceptable’s invokeMethod() hijacks all calls to the object.

 class Phone implements GroovyInterceptable {
 
   def redial() { System.out.println "redial called..." }
   def keypad() { System.out.println "keypad called..." }
   def makeCall() { System.out.println "makeCall called..." }

   def invokeMethod(String name, args) {
  
      System.out.print("Call to $name intercepted... ")

      if (name != 'keypad') {
           System.out.print("running filter... ")
           Phone.metaClass.getMetaMethod('keypad').invoke(this, null)
      }

      def validMethod = Phone.metaClass.getMetaMethod(name, args)
      if (validMethod != null) {
           validMethod.invoke(this, args)
      } else {
           Phone.metaClass.invokeMethod(this, name, args)
      }
    }
  }

 phone = new Phone()
 phone.redial()
 phone.makeCall()
 phone.keypad()
 try {
   phone.hang()
  } catch(Exception ex) {
     println ex
 }

The output shows the proper interception of methods:

Call to redial intercepted... running filter...  keypad called...

redial called..

Call to makeCall intercepted... running filter...   keypad called...

makeCall called...

Call to keypad intercepted... keypad called...

Call to hang intercepted... running filter... keypad called...

groovy.lang.MissingMethodException:  No signature of method: Car.speed()  is applicable for argument types: () values: [ ]

 

Intercepting Methods Using MetaClass

If we don’t have the privileges to modify the class source code ,in this case we may decide at runtime to start intercepting calls based on some condition or application state. In these cases, we can intercept methods by implementing the invokeMethod() method on the MetaClass

   class Phone implements GroovyInterceptable {
 
       def redial() { System.out.println "redial called..." }
       def keypad() { System.out.println "keypad called..." }
       def makeCall() { System.out.println "makeCall called..." }
   }

   Phone.metaClass.invokeMethod = { String name, args ->

   if (name != 'redial') {
     System.out.print("Call to $name intercepted... ")
     System.out.print("running filter... ")
     Phone.metaClass.getMetaMethod('redial').invoke(delegate, null)
   }

  def validMethod = Phone.metaClass.getMetaMethod(name, args)
  if (validMethod != null) {
     validMethod.invoke(delegate, args)
  } else {
     Phone.metaClass.invokeMissingMethod(delegate, name, args)
  }
 }

  phone = new Phone()
  phone.redial()
  phone.makeCall()
  phone.keypad()

 try {
   phone.hang()
 } catch(Exception ex) {
    println ex
 }

Let’s observe the method interceptions in the output:

Call to redial intercepted... running filter... keypad called...

redial called...

Call to makeCall intercepted... running filter... keypad called...

makeCall called...

Call to check intercepted... keypad called...

Call to speed intercepted... running filter... keypad called...

groovy.lang.MissingMethodException: No signature of method: Car.speed() is applicable for argument types: () values: [ ]

 

There are two differences between these two versions of invokeMethod()  we implemented on Phone, The first difference is the use of delegate instead of this. The delegate within the intercepting closure refers to the target object whose methods are being intercepted. The second difference is where we call invokeMissingMethod() on the MetaClass instead of calling invokeMethod. We’re already in invokeMethod(), so we should not call it recursively here.

 

Hope it helps!

 

About Author

Author Image
Jasgeet Singh

Jasgeet is a Sr. Lead developer .He is an experienced Groovy and Grails and has worked on designing & developing B2B and B2C portals using Grails technologies.

Request for Proposal

Name is required

Comment is required

Sending message..