APPENDIX A

The Groovy Language

Groovy is an all-purpose programming language for the JVM. It was born in 2003 when James Strachan and Bob McWhirter founded the Groovy project with the goal of creating a glue language to easily combine existing frameworks and components. Groovy is a language that aims to bring the expressiveness of languages such as Ruby, Lisp, and Python to the Java platform while still remaining Java friendly.

It attracted much excitement with these ambitious goals, because the majority of other scripting languages on the Java platform either used an entirely alien syntax and APIs or were simply Java without the need to specify types.

Despite its youth, Groovy is a stable, feature-rich language that forms the perfect base for Grails. This is a fantastic achievement, given the limited resources available to an open source project such as Groovy.

Groovy was an obvious choice as a platform for the Grails framework, because it provides the necessary underlying infrastructure to create the diverse range of miniature domain-specific languages utilized throughout Grails.


Note Martin Fowler has written an excellent article about domain-specific languages:http://www.martinfowler.com/bliki/DomainSpecificLanguage.html.


What does this mean? Well, the syntax you see used throughout the book has often been magically enhanced and shortened by using a combination of Groovy's already concise syntax and its support for metaprogramming. Groovy performs a lot of magic under the covers, abstracted away from the developer. This removes the burden from the programmer who would otherwise be required to write reams of unnecessary, repetitive code.

Before we start our journey through the diverse syntax offered by Groovy, it is worth understanding how it compares to its cousin Java. In the next section, you will see how seam-lessly Groovy integrates with Java at the syntax level.

Groovy and Java: A Comparison

Groovy's resemblance to Java is often quite striking. Some Groovy code is almost indistinguishable from Java. If your Groovy code looks too much like Java, you can improve its expressiveness by writing more idiomatic Groovy. Groovy code, when written by an experienced Groovy developer, typically occupies 40–60 percent fewer lines of code when compared to the equivalent Java. In the following sections, we'll cover the key similarities and differences between Groovy and the Java language.

What's the Same?

Java and Groovy actually have many similarities. This is what makes Groovy so appealing from a Java developer's perspective. There is no huge mental shift necessary to start working with Groovy. The Groovy syntax can almost be seen as a superset (although this is not the case) of the Java language, with the following taken directly from Java's syntax:

  • Keywords and statements
  • try/catch/finally exception handling
  • Class, interface, field, and method definitions
  • Instantiation of objects using the new operator
  • Packaging and imports
  • Operators, expressions, and assignment
  • Control structures
  • Comments
  • Annotations, Generics, static imports, and enum types from Java 5

More importantly, though, Groovy shares the same object and runtime model as Java, so the infrastructure that you are operating in (the JVM) is the same. What does this mean? Well, although Groovy is a dynamic language like Ruby or Python, it is not interpreted. All Groovy code, be it executed as a script or a fully qualified class, is compiled down to byte code and then executed.

You shouldn't underestimate the significance of this, because it means that a Groovy class is a Java class and that Groovy and Java can interoperate with each other seamlessly. A Java class can call methods on a class implemented in Groovy without ever knowing any different.

So, that's what is the same; again, we've given a brief overview, but really the similarities become obvious quite quickly once you start working with Groovy. Of equal significance, however, is what is different about Groovy.

What's Different?

One of the things that makes Groovy different is that a number of things are optional, including parentheses, return statements, and semicolons at the end of statements.


Note The rules that govern optional parentheses are unambiguous, but it's generally good style to include parentheses in all but the simplest of cases (for example, in a println statement).


In addition, some import statements are optional, because Groovy automatically imports the following packages for you:

  • groovy.lang.*
  • groovy.util.*
  • java.lang.*
  • java.util.*
  • java.util.regex.*
  • java.net.*
  • java.io.*
  • java.math.BigDecimal, java.math.BigInteger

Besides these differences, Groovy's main goal is to add features that make the common tasks faced by Java developers trivial. To facilitate this, Groovy supports the following:

  • Closures (similar to anonymous code blocks but with different scoping rules)
  • Advanced String support with interpolation (described in the "Groovy Strings" section of this chapter), regular expressions, and template generation
  • True object oriented programming with autoboxing/unboxing
  • Operator overloading and syntactic structures to ease access to existing Java classes
  • Improved syntax for existing data types augmented by new types
  • An extended library of methods onto existing Java classes

At this point, we've tackled many of the similarities and differences with Java but have yet to show any actual code. In the next section, you'll start your journey into Groovy by getting the basics right first.

The Basics

The Groovy syntax is extremely closely aligned to that of Java; this does not mean you can copy and paste Java code into Groovy, and vice versa (although in some cases this does work), but it does mean that it all feels very familiar.

Fundamentally, Groovy can be written either in classes or as a script. Implementing the "Hello World!" example as a Groovy script would involve one line of code:

println 'Hello World!'

Assuming you've saved this code in a file called Hello.groovy, executing it is trivial too:

groovy Hello.groovy

Groovy automatically creates an executable class from the script. The reason this is highlighted is that it is important to note that even though no class has been declared, the previous code will inevitably still become a class that extends groovy.lang.Script.


Note The groovy.lang.Script class is the superclass used by Groovy to provide support for running arbitrary snippets of code as scripts.


Like Java, everything in Groovy must be a class.

Declaring Classes

Class declaration is simple and familiar enough. Listing A-1 shows an example of a simple HelloController class from a Grails application.

Listing A-1. HelloController.groovy

class HelloController {
     def world = {
          render "Hello World it's " + new java.util.Date()
     }
}

Here we have defined a class called HelloController that contains a single property called world. The property itself has been assigned a value, which is a closure. Java developers may be a little confused at the moment as how this simple declaration can be a property given the verbosity of the property syntax in Java.

Essentially, another difference from Java is that Groovy has no concept of the default visibility (also known as package-level visibility). Instead, properties declared at the default level, without any explicit modifiers such as private, protected, or public, are assumed to be JavaBean properties, and the appropriate getters and setters are generated for you.

The lack of default visibility also becomes clear when defining methods, because methods are assumed to be public if no modifier is specified.

In the next few sections, we'll cover some of these, as well as some of the other powerful features that Groovy offers, starting with built-in assertions.

Language-Level Assertions

Assertions are a concept introduced to the Java language in JDK 1.4 that allow you to verify application state at a certain point. Like Java, Groovy has an assert keyword.

Assertions are primarily useful to avoid the scenario where code is executed under an invalid state and, to this end, are a useful debugging tool. In terms of this book, assertions are also useful for revealing what the current state of an executing Groovy program is. Listing A-2 shows an example of an assertion in action.

Listing A-2. Groovy Assertions

def num = 1
...
assert num == 1

Here we simply verify that the variable called num still has a value of 1 at the point of execution in the code. Assertions will be utilized throughout many of the following examples, including in our coverage of Groovy strings, which we'll cover next.

Groovy Strings

Groovy supports a concept found in many other languages such as Perl and Ruby called string interpolation. Because this is rather a mouthful in Groovy-land, they're simply (or comically, depending on which way you look at it) known as GStrings.

A GString is just like a normal string, but it allows the embedding of variables within it, using the familiar ${..} syntax found in many popular Java frameworks including Spring, Ant, and an array of view technologies. The curly braces can be omitted if it is simply the variable name that is required. Listing A-3 also demonstrates another powerful feature of Groovy's string support: multiline strings. These are defined with the triple-quotation syntax.

Listing A-3. GStrings in Action


def person = "John"

println """
${new Date()}

Dear $person,

This is a Groovy letter!

Yours Sincerely,
The XYZ Company
"""

On the first line of the listing, a variable called person is defined that is then later referenced from the String itself. The multiline String can span several lines and includes all new line characters, tabs, and spaces in its output. The resulting output of the listing is as follows:


Wed Jan 14 06:20:58 BST 2009

Dear John,

This is a Groovy letter!

Yours Sincerely,
The XYZ Company

Coming from Java, where every new line has to be closed with a quote and contain the + concatenation character, this example comes as rather a relief. This also brings us nicely to another difference from Java in the way that Groovy interprets strings vs. characters. In Java, a character is defined using the single-quotation syntax, while in Groovy it could represent either a regular String (that is, one not of the GString variety) or a character. For example, the declarations in Listing A-4 are all valid in Groovy, while in Java the first and third would produce compilation errors.

Listing A-4. String and Characters in Groovy

String hello = 'Hello' // a regular String
String greeting = "$hello World!" // a GString
def c = ' ' as char // A java.lang.Character new line character
char c = ' ' // the same as above

Believe it or not, there is yet another alternative for declaring strings in Groovy. It is known as the slashy syntax and allows easy definition of regular expressions (regex) without the need to introduce escape characters as with Java.


Note Regular expressions are a way of doing pattern matching against strings. Commonly referred to as regex, they define a set of matching operators that can be used to match almost any pattern in a string. A full discussion of regex is beyond the scope of this book, but many references are available online about the topic.20


This allows you to omit the backslash () escape character that cripples Java's regex support. Consider the example in Listing A-5.

Listing A-5. Groovy vs. Java Regex

def file = /C: hiswill eedescapingafile.pdf/
// This is what you need in Java
assert file ==~ "\w{1}:\\.+\\.+\\.+\\.+\\.+\.pdf"
// And here is how you do it in Groovy
assert file ==~ /w{1}:\.+\.+\.+\.+\.+.pdf/

This example attempts to match a file reference on a Windows system. Since Windows uses the backslash character in file references, it means you would need to escape every one of these in the Java regex expression on line 3 twice—once because Java requires you to escape the backslash character and again because so does regex!

But thanks to Groovy's slashy syntax, on line 5 you are able to avoid this particular nightmare by at least having to escape the backslash character only once.

In addition to the slashy syntax, Groovy's regex support goes even further, with support for specialized regex operators, some examples of which are shown in Listing A-6.

Listing A-6. Groovy Regular Expressions

1 import java.util.regex.*
2
3 // usage of the matching operator, which returns a Boolean
4 assert 'abababab' ==~ /(ab)+/
5
6
7     // Here the pattern operator is used
8    // to create a java.util.regex.Pattern instances
9     def pattern = ~/foo/
10   assert pattern instanceof Pattern
11
12  // The matcher operator allows you to create a
13  // java.util.regex.Matcher instance
14  def matcher = "cheesecheese" =~ /cheese/
15  assert matcher instanceof Matcher

The first example on line 4 uses the match ==~ operator, which will attempt to match the entire string against the provided regex. Next, line 9 demonstrates how to create an instance of java.util.regex.Pattern using the pattern operator.

Essentially, by starting a string with th~; character, it creates the Pattern instance instead of a String. The pattern operator is commonly seen applied directly before slashy strings in the format ~/.../ but can in fact be applied to any string.


Note It is important to notice the space between the equals sign and the ~ character that differentiates the pattern operator from the find =~ operator on line 14.


Lastly, the find =~ operator on line 14 will find the first match in the supplied String and, if used in an assignment as shown in the example, will return a java.util.regex.Matcher instance. A full discussion on regular expressions is rather beyond the scope of this book; nevertheless, what you have seen so far serves to introduce the capabilities Groovy has to offer in terms of regex support.

The next section should be pretty interesting as we explore Groovy's closure support. The closure, as a construct, is beginning to get much traction among the software development community as the benefits (and also the limitations of languages that don't have them) have started to become abundantly clearer.

Closures

Closures can essentially be seen as reusable code blocks (often called anonymous code blocks). At the syntax level, they are a sequence of statements surrounded by curly braces. They can be quite difficult to understand in the beginning at a conceptual level, but once you begin using them, it becomes hard to imagine how you ever lived without them.21 Let's take a look at the basic example shown in Listing A-7.

Listing A-7. Simple Closure

def square = { it * it }
assert [1,4,9] == [1,2,3].collect(square)

The previous example is similar to creating a function pointer in C, although the behavior of closures differs significantly. First you define a closure and assign it to a variable called square that takes the default argument and multiplies it by itself. The default argument in Groovy is called it and becomes useful for simple definitions.

The square closure is then passed to another of Groovy's built-in methods called collect that will collect each element from the list and apply the passed closure to its value. In this case, the result is a list of numbers that represent the square root of each element in the original list.

Clearly, it's useful to be able to pass blocks of code around in this fashion, but another useful way to use closures is inline as an argument to a method. This is like using an anonymous inner class in Java, except the syntax is significantly more elegant, as Listing A-8 demonstrates.

Listing A-8. Groovy step Method

def lastRevision = 0.9
0.1.step(lastRevision, 0.1) { currentRevision ->
   println( currentRevision )
}

The previous code steps through all the revisions of an imaginary version control repository and outputs each revision number. The last argument of the method is a closure, which is executed on each iteration (or step, if we're using the method's verb).


Note The step method itself takes three arguments. The last of these is a closure instance. Note how Groovy allows the closure to be specified at the end of the expression.


Clearly, closures take some getting used to when coming from Java, but if you think of them as a type of anonymous inner class, it will go a long way to aid your understanding. You'll see many more examples of their usage in the coming chapters as well as see them combined with another powerful Groovy concept: builders.

In the next section, we'll look at how Groovy greatly simplifies the Java collections API by providing language-level constructs for common Java types, as well as one of its own.

Lists, Maps, and Ranges

Groovy contains first-class constructs for two of the most commonly used collections in Java: List and Map.

This new syntax, combined with operator overloading and additional methods that use closures (provided by Groovy to extend the Java collection API), is a powerful combination best illustrated with some examples. See, for instance, Listing A-9.

Listing A-9. Collections in Action

1    // prints 1 2 3 separated by new lines to standard out
2   [1,2,3].each { num -> println num }
3   // create an empty list
4   def list = []
5   // use overloaded left shift operator to append items
6   list << 'one' << 'two' << 'three'
7   // check that we have 3 items
8   assert list.size() == 3
9   // Use Groovy's findAll method to find all words containing the letter "o"
10  assert list.findAll { item -> item.contains('o') }.size() == 2
11  // Merges a list into a string using the supplied string
12  assert list.join(',') == 'one,two,three'
13
14  // map of contact numbers
15  def contacts = [ Fred : '903-0200-1565',
16                     Wilma: '903-0207-7401' ]
17  contacts.each { key, value ->
18      println "calling $key on $value"
19  }
20  // add new contact
21  contacts.Dino = '903-0207-0349'
22  assert contacts.size() == 3

Here you can see various usages of Groovy lists and maps. First in line 2 there is an example of using Groovy's each method to iterate over a list of integer values:

2   [1,2,3].each { num -> println num }

The example calls each directly on the list definition and prints each element of the list using println, resulting in this output:


1
2
3

Next, there is an interesting use of the left shift << operator to append elements to the list. In Groovy, the left shift operator is generally available on all objects that have the concept of appending such as lists, buffers, and streams:

6   list << 'one' << 'two' << 'three'

Groovy then checks the size of the list using the size method. The size method is interesting in that even though it does exist for collections, it can be used on pretty much any object that has the concept of size or length. Java is extremely inconsistent in its handling of size and length, and there are different ways to obtain this information, depending on whether you are working with strings, arrays, or collections. Groovy attempts to unify this into a single method:

8   assert list.size() == 3

Here, on line 10 Groovy's findAll method is used on the list to locate all strings within the list that contain the letter O. The closure passed to findAll is evaluated as the criteria on each element of the list:

10  assert list.findAll { item -> item.contains('o') }.size() == 2

Another useful method in the toolbox is join, which allows you to merge any list or array into a string using the passed arguments as the separator. Here you create a comma-separated string of all elements in the collection:

12  assert list.join(',') == 'one,two,three'

The next example demonstrates Groovy's built-in syntax for defining maps:

15  def contacts = [ Fred : '903-0200-1565',
16                   Wilma: '903-0207-7401' ]

Here you create a java.util.Map that has two elements representing contact information for Fred and Wilma. Groovy allows you to omit the quotes around keys within the map syntax, so the keys Fred and Wilma in the example translate into strings.


Note The map concept in Java is equivalent to what is known as a hash in many other languages. In fact, the default implementation used is java.util.LinkedHashMap.


Sometimes you want to use something other than a string as the key and want to resolve an object from the surrounding scope as the key. If this is the case, you need to surround the key with brackets (...).

Lines 17–19 in the example demonstrate how you can use the each method to iterate over a map in the same way as other collection objects, with the key and value as arguments to the method. More interestingly, however, is the use of the dereference operator on line 21:

21 contacts.Dino = '903-0207-0349'

This will actually create a new key called Dino, with the value being the telephone number. Why is this interesting? Well, it allows you to treat maps almost like dynamic objects. Speaking of dynamic objects, there is a particular type of Groovy object called Expando.

Expando Objects

It is often useful to be able to create an object dynamically at runtime, particularly if it is not a frequently used one that warrants a class definition. This is where Expando comes in handy. Consider the example in Listing A-10.

Listing A-10. Expandos in Action

fred = new Expando()

fred.firstName = "Fred"
fred.lastName = "Flintstone"

fred.age = 45
fred.happyBirthday = {
    fred.age++
}

fred.happyBirthday()
assert fred.age == 46

As you can see, Expando allows you to programmatically define an object, its properties, and its methods at runtime. This example creates an Expando object called fred and then simply goes about assigning some properties with some initial values. A method is defined by setting a closure to a property that can be later called like a regular method.

So far, you've seen quite a range of Groovy features, and with that particular pun out of the way, we're going to move onto another type introduced by Groovy: ranges.

Ranges

Groovy supports the concept of inclusive and exclusive ranges at the language level. A range consists of a left value and a right value, with a strategy for moving from left to right. Ranges can be used on numbers, strings, dates, and any other object that implements the Comparable interface and defines next and previous methods.


Note The java.lang.Comparable interface is Java's way of comparing two objects. It defines a single method called compareTo(Object) that returns an integer. The method should return 1 if the passed object is greater than this object, −1 if it is less than this object, and 0 if they are equal.


Listing A-11 shows some examples of using ranges in combination with Groovy's advanced switch statement.

Listing A-11. Ranges in Action

def person = Expando()
person.name = "Fred"
person.age = 45

def child = 0..16 // inclusive range
def adult = 17..<66 // exclusive range
def senior = 66..120 //

switch(person.age) {
       case child:
            println "You're too young ${person.name}!"
       break
       case adult:
            println "Welcome ${person.name}!"
       break
       case senior:
           println "Welcome ${person.name}! Take a look at our senior citizen
rates!"
       break
}

This example has three ranges plus Groovy's advanced switch capabilities to print different messages depending on the age of the user. Ranges are commonly used in Groovy as a replacement for the traditional Java for loop using Groovy's for..in syntax and in combination with the subscript operator.

Listing A-12 shows how to use the for loop with a range applied to a String using the subscript operator.

Listing A-12. The Groovy for Loop and Ranges

def text = 'print me'
for(i in 0..<4) {
    println text[i]
}
assert 'print' == text[0..4]

Here, you're looping through the first four characters of the supplied text (remember, the previous example is an exclusive range) and printing out each character. The output of the for loop equates to the following:


p
r
i
n

And that concludes this whirlwind tour of Groovy basics. You've explored a lot, and although this section is by no means comprehensive, it should give you an idea of what Groovy is capable of as a general-purpose language.

In the next section, you'll start to explore the features that make Grails a possibility. What you've seen so far is great, but there is much more to Groovy, making it one of the most powerful dynamic languages available on the JVM today.

Groovy Power Features

The next sections are by no means a prerequisite for using Groovy, but they will help you understand what makes Groovy so powerful when compared to some of its sister dynamic languages that run on the JVM.

You'll explore three features in particular detail:

  • True object oriented programming
  • Metaprogramming
  • Builders

Everything Is an Object

Unlike Java, which mixes primitive and reference types, in Groovy everything is an object. How does Groovy manage this while maintaining integration with Java? Well, before Java 5.0 was even introduced with Generics and autoboxing, Groovy was doing this for you in Java 1.4.

When a primitive type gets passed into the Groovy world, it is automatically "boxed" into its object equivalent, and vice versa. This allows Groovy to support some interesting concepts, which we will cover in the following sections:

  • Methods on primitives
  • Operator overloading
  • The Groovy truth

In this respect, Groovy is far closer to object-oriented languages such as Smalltalk than Java, since even operators such as ==, !=, +, and are translated into method calls at runtime.


Note Groovy's == operator differs from Java's in that it does not evaluate object identity, but it delegates to the object's equals method. For object identity, Groovy introduces a special is method: left.is(right).


To get you on your way to understanding the implications and possibilities that true object oriented programming offers, the first thing we're going to look at is Groovy's ability to support methods on primitives.

Methods on Primitives

Since Groovy performs autoboxing at runtime, you automatically have all the methods available in the concrete class equivalent (the Java primitive type int becomes java.lang.Integer, for example) as well as some additional ones provided by Groovy.

Combine this feature with Groovy's closure support, and having methods on primitives provides some interesting use cases. Listing A-13 provides various examples of calling methods on integers.

Listing A-13. Methods on Numbers

3.times {
      println it
}
// iterates from 3 to 9
3.upto(9) {
      println it
}
// iteratives from 3 to 9 in increments of 3
3.step(9,3) {
      println it
}

The previous examples provide a little taster of what allowing methods on primitive types means to Java developers. For others, this may not seem so revolutionary, but it's another string to Groovy's bow.

Operator Overloading

Operator overloading, which has a love-hate relationship in the world of C++, has been incorporated into the Groovy language in an extremely elegant fashion. As mentioned previously, Groovy is a true object-oriented language, and this extends to the operators themselves. Operators in Groovy are just method calls that follow a naming convention.

Table A-1 lists the Groovy operators and their equivalent methods; to utilize operators, simply add the necessary method to your object.

Table A-1. Groovy Operator Method Names

Operator Method
a + b a.plus(b)
a - b a.minus(b)
a * b a.multiply(b)
a / b a.divide(b)
a++ or ++a a.next()
a-- or --a a.previous()
a[b] a.getAt(b)
a[b] = c a.putAt(b, c)
a << b a.leftShift(b)

It doesn't end here, however; Groovy also uses operator overloading to overload the comparison operators. Table A-2 shows these operators and the methods or expressions they evaluate to.

Table A-1. Groovy Comparison Operator Method Names

Operator Method
a == b a.equals(b)
a != b ! a.equals(b)
a <=> b a.compareTo(b)
a > b a.compareTo(b) > 0
a >= b a.compareTo(b) >= 0
a < b a.compareTo(b) < 0
a <= b a.compareTo(b) <= 0

In addition, Groovy provides a number of built-in operators on common Java types that let you work with them in intuitive ways. As an illustration, you can use the left shift << operator to do the following:

  • Append an item to a java.util.List
  • Output data to a java.io.Writer or a java.io.OutputStream
  • Append characters onto a java.lang.StringBuffer

Groovy provides many more such operators across the JDK classes—too many to list here—so it is worthwhile to explore what is available in terms of operators within the Groovy documentation and source code. As your knowledge of Groovy grows, you will find yourself using them more and more and even providing your own.

The Groovy Truth

What is true and what isn't is very different in Groovy in comparison to Java, but not in a bad way. The phrase "the Groovy Truth" was coined by Dierk Koenig, Groovy committer and author of Groovy in Action22 to differentiate Groovy's concept of what is true and what is not. As an example, the following, by no means comprehensive, list can be passed to if statements in Groovy and will evaluate to false:

  • A null reference
  • An empty or null string
  • The number zero
  • A regex Matcher that doesn't match

This makes for infinitely cleaner code and decreases the burden on the programmer to make sure that null checks are valid, that they're checking that a string is not null and is not zero length (boy, that's a mouthful), and that they're checking a whole hoard of other possibilities that cause error-prone code.

In the context of web applications, this is extremely useful given the amount of string evaluation necessary (remember, request parameters come in as strings).

Using the Groovy Truth, the if, while, and assert statements become rather more intelligent than their equivalents in Java. However, it simply wouldn't be Groovy if it wasn't taken even further. In Java, the switch statement is rarely used. Why? Well, it's fairly limiting in that it operates only in conjunction with the int or char primitive types (as well as Enum since Java 5).

In Groovy, however, the switch statement is your best friend and one of the more frequently used constructs. Groovy's switch accepts any object that implements the method isCase. Default implementations of isCase are provided for many of the commonly used types; if none is provided, then isCase simply delegates to the equals method. Listing A-14 shows the switch statement in action and how it can be used in conjunction with a variety of types.

Listing A-14. Usage of Groovy Switch

switch (x) {
      case 'Graeme':
        println "you're Graeme!"
        break
      case 18..65:
        println "ok you're old enough"
        break
      case ~/Gw?+e/:
        println 'your name starts with G and ends in e!'
        break
      case Date:
        println 'got a Date instance'
        break
      case ['John', 'Ringo', 'Paul', 'George']:
        println "You're one of the Beatles! "
        break
      default:
        println "That is something entirely different"
    }

The previous example is just a taster of what is possible with the Groovy switch. Try doing some experiments of your own to get used to the behavior of switch and how isCase behaves for each type.

Given what you've seen so far of Groovy's ability to dynamically dispatch operators and methods and box primitive types in objects, you would think that we've covered the parts that make Groovy truly dynamic. Not quite. In the next section, we'll cover Groovy's metaprogramming support, which makes Groovy extremely compelling and powerful and helps put it on an even keel with languages such as Ruby and Python.

Metaprogramming

Any concept that has a colorful name such as metaprogramming sounds scary, but fundamentally metaprogramming in Groovy is the ability to add behavior to classes at runtime. You've seen this in action many times already with Groovy's seemingly magical ability to add new methods to existing Java classes.

Given that Java's class-loading mechanism dictates that classes, once loaded, cannot be changed, you may be wondering how this is possible at all.

What Groovy does is that for every class loaded by the Groovy runtime there is an associated MetaClass that is used when dispatching methods to the class itself. Think of it in terms of a proxy that delegates to the actual implementation. The remarkable thing with Groovy, however, is that it doesn't just cover method dispatching. Constructors, fields, operators (because of operator overloading), properties, static, and instance methods can all be added, intercepted, or modified at runtime thanks to Groovy's Meta Object Protocol (MOP).

Outside of Groovy, the way this has been done is through software tools such as AspectJ, an implementation of Aspect-Oriented Programming (AOP) for Java, which does byte code weaving. In Groovy, byte code manipulation is unnecessary, and through Groovy's meta facility, Grails is able to perform a lot of magic in one line of code that would otherwise have taken reams of complicated Java code.

None of Grails' classes extends any special framework-specific classes, and the necessary behavior is instead injected into your classes at runtime via the MetaClass. Let's step through a few examples of how Groovy makes all this possible through its metaprogramming APIs.

Inspecting the MetaClass

As mentioned, every java.lang.Class has an associated groovy.lang.MetaClass instance. The MetaClass for a given Class can be obtained using the metaClass property on any instance. For example, if you wanted to find out all the methods available on a given instance, you could use the metaClass property, as shown in Listing A-15.

Listing A-15. Inspecting Methods at Runtime Using the MetaClass

def text = "hello world"
text.metaClass.methods.each { method ->
       println method.name
}

The code in Listing A-15 uses the methods property of the MetaClass, which returns a list of groovy.lang.MetaMethod instances, to output each method name, resulting in output such as the following:


replaceAll
replaceFirst
split
split
startsWith
startsWith
subSequence
substring
substring
toCharArray
toLowerCase
...

As well as the methods property, a properties property will obtain a list of groovy.lang.MetaProperty instances representing each property available on an instance. Occasionally, you'll just want to find whether an individual instance has a particular method or property and act accordingly. Listing A-16 shows how you can use the respondsTo and hasProperty methods to achieve this.

Listing A-16. Using respondsTo and hasProperty

def text = "hello world"
if(text.respondsTo("toUpperCase")) {
     println text.toUpperCase()
}
if(text.hasProperty("bytes"))
{
     println text.bytes.encodeBase64()
}

The technique in Listing A-16 is often referred to as duck typing, a term that originates from the saying, "If it walks like a duck and quacks like a duck, I would call it a duck." In other words, in dynamic languages, objects can fulfill an implicit contract through duck typing, without needing to implement any special interface, as you would be required to do in a statically typed language like Java.

Adding Behavior at Runtime

Much of the Grails magic involves adding behaviors, in the form of methods, properties, and constructors, at runtime. In early versions of Grails, this was done through custom MetaClass implementations. However, this soon grew tedious, and the developers of Grails ended up creating a special kind of MetaClass called the ExpandoMetaClass.

ExpandoMetaClass provided a DSL for modifying MetaClass instances, and after stabilizing from its roots in the Grails project, ExpandoMetaClass soon became part of the Groovy language itself. Adding methods using ExpandoMetaClass is incredibly easy. Listing A-17 shows an example that adds a method called swapCase to the String class.

Listing A-17. Adding Methods to Classes at Runtime Using ExpandoMetaClass

String.metaClass.swapCase = {->
      def sb = new StringBuffer()
      delegate.each {
           sb << (Character.isUpperCase(it as char) ?
                        Character.toLowerCase(it as char) :
                        Character.toUpperCase(it as char))
      }
      sb.toString()
}
assert "Hello".swapCase() == "hELLO"

As you can see from Listing A-17, you can add or override methods at runtime by assigning a closure to a property of the MetaClass. Within the scope of the closure, the delegate variable is equivalent to this in a standard method.

This is exactly how the APIs such as GORM, discussed in Chapter 10, work. Grails inspects all the domain classes within a project and automagically adds new behavior to each one. Since the Grails runtime constructs a Spring ApplicationContext, closures can be used to inject methods that interact with Spring and Hibernate.

Listing A-18 shows an example of how the save method looks in Grails internally.

Listing A-18. Adding the save Method at Runtime

def t = new HibernateTemplate(applicationContext.getBean("sessionFactory"))
for(domainClass in application.domainClasses) {
        domainClass.metaClass.save = { t.saveOrUpdate(delegate) }
}

The real implementation is a bit more involved than that, but at a simple level Listing A-18 serves to demonstrate the concept. Of course, Groovy doesn't allow the addition of just instance methods but static methods, constructors, and properties too. Listing A-19 shows a few examples of adding different kinds of behaviors.

Listing A-19. Enhancing the Behavior of a Class

def dateFormat = new java.text.SimpleDateFormat("MM/dd/yyyy")
// Add a static method
Date.metaClass.static.format = { fmt -> dateFormat.format(new Date()) }
// Add a property
String.metaClass.getDate = {-> dateFormat.parse(delegate) }
// Add a constructor
String.metaClass.constructor { Date d -> dateFormat.format(d) }

String today = Date.format()
println "Today is $today"
Date todaysDate = today.date
today = new String(todaysDate)
println "Today is still $today"

As you can see from Listing A-19, with Groovy's metaprogramming capabilities you can modify and extend pretty much any aspect of a class behavior. However, it is not just classes that can be altered. Groovy also supports per-instance modifications of behavior. In Listing A-19, the changes to the MetaClass apply globally because the code is using the metaClass property of the java.lang.Class instance that is being modified.

To apply behavior to only one instance, you can use the metaClass property of the instance, in which case only that instance will be altered. This has several advantages; the major one is that changes to behavior can be isolated to the thread that the instance is created in. Global modifications apply to all threads, so should only ever be made once at start-up time to avoid inconsistent behavior.

Listing A-20 shows an example of adding the swapCase method from Listing A-17 to an instance of java.lang.String.

Listing A-20. Using Per-Instance Metaprogramming

def text = "Hello".

text.metaClass.swapCase = {->
      def sb = new StringBuffer()
      delegate.each {
           sb << (Character.isUpperCase(it as char) ?
                        Character.toLowerCase(it as char) :
                        Character.toUpperCase(it as char))
      }
      sb.toString()
}
assert text.swapCase() == "hELLO"

The examples of metaprogramming you have seen so far are neat, but many languages (including JavaScript and Python) allow you to add methods at runtime. However, Groovy belongs to a select group of languages that takes this concept even further by allowing you to modify the semantics of a program by intercepting method dispatch itself. In the next section, we'll cover how to achieve this.

Intercepting Method Dispatch

You can intercept method dispatch in Groovy in a number of ways. If you're the author of the class, then a trivial way is just to override the invokeMethod method. When you implement invokeMethod, Groovy will route all calls to methods that don't exist to your invokeMethod implementation.

Listing A-21 shows a trivial implementation that simply prints out the current method name, instead of throwing an exception, if a method doesn't exist.

Listing A-21. Overriding invokeMethod

class InterceptAndPrint {
   def out
   InterceptAndPrint (out) { this.out = out }
   def invokeMethod(String name, args) {
        out << name
   }
}
def i = new InterceptAndPrint (System.out)
i.hello()
i.world()

As you can see, by implementing invokeMethod, you can change the way Groovy's method dispatch is represented at runtime. You can achieve the same thing with properties by overriding the getProperty(name) and setProperty(name, value) methods.

Intercept, Cache, Invoke

As you saw in the previous section, you can intercept method dispatch by overriding the invokeMethod method. This is a pretty powerful pattern because you're injecting new behavior into your application. However, it has its overheads because Groovy has to go through various layers of dispatch logic before eventually reaching the invokeMethod method.

Another approach is to take advantage of code synthesis using the Intercept, Cache, Invoke pattern. The basics steps are as follows:

  • Intercept: Intercept failed method dispatch using the methodMissing method.
  • Cache: Create a new method on the fly, caching the behavior in the MetaClass.
  • Invoke: Invoke the new behavior and return the result.

The advantage of this approach is that many new methods can be created at runtime. These new methods will incur a cost on first creation, but subsequent calls to the same method will be quicker. This is the technique that GORM uses to implement dynamic finders, a subject discussed in Chapter 10.

Listing A-22 shows an example of how you could implement your own version of dynamic finders using raw SQL instead of Hibernate using the methodMissing hook.

Listing A-22. Implementing Intercept, Cache, Invoke

url = "jdbc:hsqldb:mem:testDB"
driver = "org.hsqldb.jdbcDriver"
user = "sa"
pass = ""
Album.metaClass.static.methodMissing = { String name, args ->
     if(name.startsWith("findBy") && args) { // intercept
          def propertyName = name[6..-1]
          propertyName = propertyName[0].toLowerCase() + propertyName[1..-1]

         def newMethod = { Object[] varArgs ->
                  def results = []
                 def sql = groovy.sql.Sql.newInstance(url,user,pass, driver)
                 sql.eachRow("select * from ${ Album.name} where $propertyName=?",
                                       [varArgs[0]] ) {
                      results << new Album (title:it.title, genre:it.genre)
                 }
                 return results
        }
        Album.metaClass."$name" = newMethod // cache
        return newMethod.call(args) // invoke
    }
    else {
         throw new MissingMethodException(name, Album,args)
    }
}

albums = Album.findByTitle("The Backroom")
albums.each {
    println it.title
    println it.genre
}

The steps of the Intercept, Cache, Invoke pattern are highlighted in bold in Listing A-22. Essentially, using methodMissing, you can intercept method dispatch, and if the method name starts with findBy, then a new method is automatically created that uses Groovy's SQL APIs to execute a query and return the results. The new behavior is then cached by creating a new method using the MetaClass at runtime:

Album.metaClass."$name" = newMethod // cache

This will ensure that the next time the method is invoked, Groovy doesn't have to go through the various phases of dispatch logic before giving up and calling methodMissing. Finally, the cached method is then invoked, resulting in the new behavior being executed:

return newMethod.call(args) // invoke

And that is how you implement GORM-style dynamic finders using raw SQL. Of course, the implementation in Listing A-22 is pretty limited compared to GORM, but you get the general idea.

The MetaClass concept in combination with Groovy's advanced syntax is also what enables a concept called builders. In the next section, we'll explain what builders are, what's the driving force behind their conception, and why they're so important to the overall picture.

Understanding Builders

A builder is an object that implements the builder pattern. The Gang of Four's book23 introduces one particular pattern known as the builder pattern. The idea behind it is to construct complex objects from another object or builder. For example, you may need to build a complex markup hierarchy with the root object being the document itself. A builder would encapsulate the logic to construct, or build, this object for you.

The builder pattern is extremely difficult to implement in Java because of the limitations of the syntax. (Some would say it is impossible and that current implementations are merely mimicking a true builder, although efforts have been made in projects such as Commons CLI and IntelliJ IDEA PSI.) Groovy, however, has no such problem, thanks to its support for named arguments, closures, and optional parentheses.


Note Groovy doesn't support true named arguments but allows the method to specify a map as the only argument, hence mimicking this capability. This limitation is mainly down to Java byte code itself, which does not associate names (only types) with method parameters.


Groovy ships with a number of builders (excuse the pun) built-in, including but not limited to the following:

  • The MarkupBuilder for constructing, typically XML, markup
  • The DOMBuilder for constructing W3C DOM trees
  • The AntBuilder to provide scripting for Apache Ant
  • The SwingBuilder for constructing Swing GUI interfaces

As an example, take a look at the usage of the MarkupBuilder, shown in Listing A-23, which allows construction of markup documents such as XML or HTML.

Listing A-23. MarkupBuilder in Action

// construct builder that outputs to standard out
def mkp = new groovy.xml.MarkupBuilder()

// write markup
mkp.authors {
      author(name:'Stephen King') {
          book( title:'The Shining')
          book( title:'The Stand')
     }
     author(name: 'James Patterson') {
         book( title:'Along Came a Spider' )
     }
}

This example demonstrates the construction of a groovy.xml.MarkupBuilder instance using standard out and the usage of closures and named arguments to represent the markup. Listing A-24 shows the result.

Listing A-24. Result of MarkupBuilder


<authors>
     <author name="Stephen King">
          <book title="The Shining" />
          <book title="The Stand" />
     </author>
     <author name="James Patterson">
          <book title="Along Came a Spider" />
      </author>
</authors>

It is interesting at this point to take a closer look at Listing A-23. In this example, we passed an "anonymous" closure to the authors() method of the MarkupBuilder instance, but consider the possibility of assigning this closure to a variable and then passing as an argument the same closure to different builders, one that renders XML and another that outputs the same data as a PDF document or renders it in a GUI.

Unlike the XML produced in Listing A-24, the builder code in Listing A-23 is pure Groovy code and can therefore leverage the full power of the language: conditionals, looping, referencing, inheritance, and so on.

Builders are an extremely powerful concept, and if you're willing to delve into some Groovy development by extending the BuilderSupport class to create your own builders, you can create some pretty amazing constructs that could end up as domain-specific languages within your application.

Grails utilizes builders all over the place, from constructing Hibernate criteria to rendering markup to the HTTP response. Builders are a key element in the conciseness and power that Grails brings to web application development.

Summary

That completes this dash through the Groovy language. As we have already admitted, it was by no means comprehensive. Groovy has many more fantastic features; it is really worth investing the time to learn more about it. But this quick overview should give you an idea of why some of Groovy's features are so important to Grails and how they make life easier developing today's web applications.

You saw that Groovy looks pretty much like Java at first glance, allowing a smooth transition into the new world of dynamic programming. Since Groovy is fully integrated with the Java platform and works directly on JDK objects, your investment in learning Java and your experience with the platform are fully protected.

What's new is that Groovy gives you more immediate control over types such as lists and maps. New concepts such as closures and ranges complete the picture. The combination of syntax enhancements, new types, improvements to JDK classes, and metaprogramming leads to an idiomatic Groovy style that is both simple and powerful.



20. Java Regular Expressions: Taming the java.util.regex Engine by Mehran Habibi (Apress, 2004) is an excellent book that covers the intricacies of regular expressions on the Java platform.

21. Many people feel now is the time for Java to introduce closure support, and this may happen in the future. See http://mindprod.com/jgloss/closure.html for information on why Java doesn't currently support closures.

22. Groovy in Action by Dierk Koenig et al. (Greenwich, CT: Manning Publications, 2007)

23. Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley, 1995)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset