Creating DSLs in Java, Part 4: Where metaprogramming matters

Experience the power of dynamic methods with Scala and Groovy

1 2 3 4 5 Page 2
Page 2 of 5

Metaprogramming

When building internal DSLs you need to be able to add methods dynamically and also to invoke methods dynamically with ease. This sort of metaprogramming is a common characteristic of newer Java-platform languages like Groovy and JRuby, but not of the Java language.

Consider the following Groovy example:

// Groovy
str = 'hello'
println str.class
println str.encrypt()

If you run the above code, you will get a MissingMethodException because java.lang.String does not have an encrypt method. Fortunately, Groovy makes it easy to add the encrypt() to the String class:

String.metaClass.encrypt = {-> '^%&$*' } 
str = 'hello'
println str.class
println str.encrypt()

My implementation of the encrypt method simply returns the String '^%&$*'. When you run the above code you will get the output

class java.lang.String
^%&$*

Note that I added the encrypt method to the metaclass of String. Because Groovy maintains a metaclass for each Java class you can easily add methods to classes at runtime. (See the Resources section to learn more about metaprogramming in Groovy.)

Method synthesis

In another application of metaprogramming, Groovy also makes it easy to synthesize methods at runtime. Listing 1 is an example of a Groovy Person class that will accept any method that starts with the name play:

Listing 1. Method synthesis in Groovy

class Person
{
  def methodMissing(String name, args)
  {
    if (name.startsWith('play'))
    {
      println "I like to play ${name.split('play')[1]}"
    }
    else
    {
      throw new MissingMethodException(name, Person, args)
    }
  }
}

peter = new Person()

peter.playTennis()
peter.playPiano()
peter.sing()

I call methodMissing the mother of all methods: it says, "if you don't find the method you're looking for, come to Mama." In that method, I check if the method name starts with play; if it does, I simply print that I like the activity mentioned (the word that follows play in the method name). Otherwise, I throw an exception that I don't recognize the method as valid. The output from the above code is shown below:

I like to play Tennis
I like to play Piano
Caught: groovy.lang.MissingMethodException: No signature of method:  
Person.sing() is applicable for argument types: () values: {} ...

As I've mentioned, metaprogramming in Groovy is a huge topic and well worth exploring. Here I've covered just enough to get you started with writing internal DSLs in Groovy.

1 2 3 4 5 Page 2
Page 2 of 5