Dynamically creating method names

ExpandoMetaClass - Dynamic method/property name creation

Since Groovy allows you to use Strings as property names this in turns allows you to dynamically create method and property names at runtime.

The Basics

To create a method with a dynamic name simply use Groovy's feature of reference property names as strings. You can combine this with Groovy's string interpolation (Gstrings) to create method and property names on the fly:

class Person {
   String name = "Fred"
}

def methodName = "Bob"

Person.metaClass."changeNameTo${methodName}" = {-> delegate.name = "Bob" }

def p = new Person()

assert "Fred" == p.name

p.changeNameToBob()

assert "Bob" == p.name

The same concept can be applied to static methods and properties.

A more elaborate example

In Grails we have a concept of dynamic codecs, classes that can encode and decode data.

These classes are called HTMLCodec, JavaScriptCodec etc. an example of which can be seen below:

import org.springframework.web.util.HtmlUtils
class HTMLCodec {
    static encode = { theTarget ->
        HtmlUtils.htmlEscape(theTarget.toString())
    }

    static decode = { theTarget ->
    	HtmlUtils.htmlUnescape(theTarget.toString())
    }
}

So what we do with these classes is to evaluate the convention and add "encodeAsXXX" methods to every object based on the first part of the name of the codec class such as "encodeAsHTML". The pseudo code to achieve this is below:

def codecs = classes.findAll { it.name.endsWith('Codec') }

codecs.each { codec ->
    Object.metaClass."encodeAs${codec.name-'Codec'}" = { codec.newInstance().encode(delegate) }
    Object.metaClass."decodeFrom${codec.name-'Codec'}" = { codec.newInstance().decode(delegate) }
}


def html = '<html><body>hello</body></html>'

assert '&lt;html&gt;&lt;body&gt;hello&lt;/body&gt;&lt;/html&gt;' == html.encodeAsHTML()

As you can see from the above we dynamically construct the names of the methods using GString expressions!