Groovy MetaClass: Overriding a method whilst using the old implementation

2009/06/1

The need to add some functionality an existing method, but avoiding cutting and pasting the old implementation has come up a few times over the last week.

Sometimes, creating a subclass isn’t feasible, often because you don’t control all of the places where that class gets used.

Calling super() without the subclass

All you need to do is to get a reference to the old method. Getting methods from the metaClass is easy, if there’s only one method signature for that method, just use the “&” operator:

def oldToOctalString = Long.metaClass.&toOctalString

If there are multiple method signatures for a method, you’ll need to use the getMetaMethod method and pass in the signature of the method you want. This is probably the safest way to ensure that you’re getting the method that you think you’re getting.

println Long.metaClass.methods.findAll { it.name == "compareTo" }.join("\n")
// prints:
// public int java.lang.Long.compareTo(java.lang.Long)
// public int java.lang.Long.compareTo(java.lang.Object)
 
def oldCompareTo = Long.metaClass.getMetaMethod("compareTo", [java.lang.Long] as Class[])

Now that you know how to get a reference to the method you want, you can redefine the method, while still letting the old method’s implementation do all the heavy lifting for you.

Here, we redefine the “plus” method on Integer to always work with absolute values, without actually getting our hands dirty in all that messy arithmetic:

def oldPlus = Integer.metaClass.getMetaMethod("plus", [Integer] as Class[])
 
Integer.metaClass.plus = { Integer n ->
    return oldPlus.invoke( Math.abs(delegate), Math.abs(n) )
}
 
assert 4 == 2 + 2
assert 4 == -2 + -2

If you don’t save the old method (or completely re-implement the logic for plus), you’ll end up in an infinite loop and throw a java.lang.StackOverflowError:

Integer.metaClass.plus = { Integer n ->
    return Math.abs(delegate) + Math.abs(n)
}
 
// DOESN'T WORK THROWS java.lang.StackOverflowError
assert 4 == -2 + -2	// FAILS!!!

This same kind of thing can be done with AOP, but that often feels more heavy than a little metaClass manipulation.

There are 4 comments in this article:

  1. 2009/06/8Josh Reed say:

    Thanks, Ted. I was just trying to figure out how to do this the other day, so this is quite timely.

    Cheers,
    Josh

  2. 2009/06/16Deepak Mittal say:

    Thanks Ted for the handy tip. I was looking for doing exactly this.

    Cheers!

    -Deepak

  3. 2009/07/31Ted Naleid » Modularizing Groovy Config Files With a Dash of Meta-Programming say:

    [...] is a continuation of a sporadic set of blog posts about some practical uses for groovy [...]

  4. 2009/09/9Föredrag: Molnarkitektur och Groovy & Grails « Jonas funderingar say:

    [...] började med att visa enkla exempel på hur man kan använda Groovys metaclass för att enkelt definiera om existerande metoder men även lägga till nya. Eftersom Groovy är [...]

Write a comment: