Jim Driscoll's Blog

Notes on Technology and the Web

Method dispatch on Groovy objects

leave a comment »

 

As I promised my post about optional parenthesis, today I’m going to talk about method dispatch in  Groovy – specifically, dynamically dispatching methods on Groovy objects via the invokeMethod mechanism.  We’ll tie it into DSL creation in a later post.

The key method to know about for method dispatch is GroovyObject.invokeMethod(String name, Object args).  This method is located on GroovyObject, and is called when the method you called isn’t present on the object.

Consider the following Groovy code:

class Test {
  def invokeMethod(String name, args) {
    println "called invokeMethod $name $args"
  }

  def test() {
    println 'in test'
  }
}

def t = new Test()
t.test()
t.bogus('testing!',1,2,3)

 

This code prints out the following text, when run in groovyConsole:

in test
called invokeMethod bogus [testing!, 1, 2, 3]

the first call goes to the test method, as usual.  The second call, instead of resulting in a MissingMethodException, will route through the invokeMethod method.

This can be handy for all kinds of things, but the use I’ve put it to is as a dispatcher, routing calls to an underlying class or set of classes – here’s an example:

 

class One {
  static def test1() {
    println 'in test1'
  }
}

class Test {
  def invokeMethod(String name, args) {
    if (One.metaClass.respondsTo(One, name, *args)) {
      return One."$name"(*args)
    }
  }
}

def t = new Test()
t.test1()

This prints out 

in test1

Now, this example is flagrantly using a few tricks in Groovy, so let me mention how they work…  (Feel free to skip this paragraph if you’re content with this being a magic incantation.)   The first bolded line, with the respondsTo method, will retrieve the metaClass of the One class, which acts in a similar way to the Class class, but allows additional capabilities.  The respondsTo method of MetaClass takes, as it’s first argument, the actual object (or class, for static methods) that you’re checking, the name of the method, and then the arguments.  The asterisk in front of the “*args” argument is called the “spread operator”, and will derefrerence the array of args to instead be a list of arguments placed at the end of the method call.  The second bolded line is using the String substitution capability of Groovy’s double quoted Strings (called GStrings) to dynamically execute the method called name, again passed the arguments with the spread operator.  An additional wrinkle is that respondsTo actually  returns a ArrayList – which is treated as false by Groovy if empty, and true if not.  Now, you could do all this in Java, via reflection and other code, but the pain of doing so really makes this something you should probably do in Groovy.

There’s one other case we should probably cover – if your class implements the marker interface GroovyInterceptable, it won’t just intercept methods it can’t find – it will intercept all method calls on the class, including methods that are actually there.  That unfortunately means that we can’t directly call the method from within the invokeMethod though – instead, you must use the metaClass to invoke the method, getting around that interception.  Here’s how:

class One {
  static def test() {
    println 'in One.test'
  }
}

class Test implements GroovyInterceptable {
  def firstTime = true
  def invokeMethod(String name, args) {
    if (firstTime) {
      firstTime = false
      return One."$name"(*args)
    }
    return metaClass.getMetaMethod(name,args).invoke(this,args)
  }
  def test() {
    println 'in Test.test'
  }
}

def t = new Test()
t.test()
t.test()

 

This prints out:

in One.test
in Test.test

 

We’ll leave the explanation of how all this works for another time – the MetaClass is used pretty heavily in all kinds of Metaprogramming in Groovy, and we’ll cover it pretty extensively as we go on – but it’s use should be obvious from context.  Note that unlike our other use of args, we do not need to use the spread operator.  But keep the MetaClass in mind, because when it comes to adding methods dynamically at runtime, it’s the way to go.

Next up, we’ll talk about the related topic of Property Dispatch.

About these ads

Written by Jim Driscoll

September 29, 2012 at 10:30 AM

Posted in DSL, Groovy

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 411 other followers

%d bloggers like this: