There are always limitations to the programming language that we use. This becomes problematic when we need to do something that our language of choice doesn’t support, especially with a static programming language like Java. We often end up extending a class through inheritance to provide this new capability or we create utility classes to meet these needs. Either one of these approaches can become cumbersome and difficult to maintain.
Enter Groovy and its metaprogramming capabilities. Metaprogramming is the ability to add new methods to classes at run-time. This capability is considered by many to be one of the most useful features of the Groovy language.
Let’s say that you need a way to insert a space between each character in a string value. This can be done using a Groovy closure.
Using a simple closure:
You could create a simple closure as a free-standing method:
def widen = {src->
def newStr = ""
for( c in src ){ // loop over the chars in a string
newStr += c + " "
}
return newStr
}
Below is how you could use this closure:
println widen(“My Page Title”)
Producing the result:
M y P a g e T i t l e
Using Closures and the ExpandoMetaClass:
Every class that is accessed by Groovy code, either a Java class or a Groovy class, is surrounded by an ExpandoMetaClass (EMC) that intercepts method calls to it. So, even though the String class is final, methods can be added to its EMC. Groovy had to introduce a new concept called delegates to make all of this work. The delegate is the class that the EMC surrounds. The keyword delegate, is similar to the java keyword this. Because of the EMC in Groovy and the new delegate concept, we are able to implement the closure method widen() on top of the Java class String.
Or, you could create a closure to add the method to the String class:
String.metaClass.widen = {->
def newStr = ""
for( c in delegate ){ // loop over the chars in a string
newStr += c + " "
}
return newStr
}
This implementation can be tested similar code to the simple closure example. This difference is that we are invoking a String method rather than a free-standing closure.
println "My Title Page".widen()
Overriding Method Behavior:
Another feature of closures and the EMC is the ability to override method behavior, without sub-classing the class in question. This allows you to alter behavior of an existing class method without changing the classes that use the method in question.
Using the example below, we can alter the behavior of the String.toUpperCase():
String.metaClass.toUpperCase = {->
return delegate.toUpperCase(Locale.ENGLISH);
}
Using this closure, you could enforce the behavior throughout your application, that all String.toUpperCase() method invocations will return the affected String value using the English Locale rules.