CHAPTER 1

image

Introduction to Groovy

Modern Java programmers live in the dissonance of two conflicting schools of thought. On one hand, dynamic languages such as Groovy, JRuby, and Jython offer advances in expressive power. On the other, many Java purists reject these languages as too impractical. Groovy with its new version addresses this conflict, establishing itself as an expedient language.

Anachronistically, as programming languages evolve in a benign continuum, one or the other contender language is impeached upon on its performance merits. However, with progressive enhancements of compilers, runtime systems, or even processing power, it became apparent that the performance penalties were not so big as envisaged. The contender language not only survived, but also had rather favorable consequences on the programming sphere. It is now apparent that Groovy is not a fad that will fade away next year or the year after.

Beautifully-engineered Groovy seamlessly integrates with the existing Java libraries and aims at dynamicity to Java without introducing a steep learning curve for Java developers. Groovy, however, is not alone in the new feature-rich JVM landscape—other languages such as JRuby, Jython, Jaskell, Clojure, Scala are its contemporaries. All these languages are designed to, when not leveraging Java, assuage some of Java’s problems. But there are a few factors that ascertain Groovy’s position as first among equals. Groovy was designed from scratch to run on Java virtual machines, as were Clojure and Scala, which gives Groovy, Clojure, and Scala few notches. Jython and JRuby were ported on JVM. Jaskell is a JVM counterpart of pure functional language Haskell. Other than execution environment, all these languages except Groovy lack Java’s immense libraries. Groovy is designed to be both source-compatible and binary-compatible with Java. This means that a Groovy class could extend a Java class or implement a Java interface, and that a Java class could extend a Groovy class or implement a Groovy interface. Grails, the leading next-generation Groovy-based framework, is built on widely-held Spring and Hibernate frameworks. Griffon, another Groovy-based MVC framework, brings a revolution in the world of desktop applications. Groovy’s source and binary compatibility with Java, combined with two Groovy-powered next-generation frameworks supported by the starfleet of SpringSource, strongly indicates that Groovy’s future is assured. It is only logical.

In this chapter, we will introduce the Groovy language, describe how to install it, and give you an idea of the benefits of Groovy over Java by working through an example. Then we will give you a general overview of key features of the Groovy language.

Installation

Groovy comes bundled as a .zip file or platform-specific installer for Windows, Ubuntu, and Debian (as well as openSUSE until recent versions). This section explains how to install the zipped version, since it covers the most platforms.

To install Groovy:

  1. Download the most recent stable Groovy binary release .zip file from http://groovy.codehaus.org/Download .
  2. Uncompress groovy-binary-X.X.X.zip to your chosen location.
  3. Set a GROOVY_HOME environment variable to the directory in which you uncompressed the .zip file.
  4. Add the %GROOVY_HOME%in directory to your system path.

To validate your installation, open a console and type the following:

>groovy -v

You should see something like this:


Groovy Version: 2.0.0 JVM: 1.6.0_31 Vendor: Sun Microsystems Inc. OS: Windows 7

Groovy by Example

The best way to grasp the power and elegance of Groovy is to compare it to Java using an example. In the remainder of this chapter, we will show you how to convert the simple Java class in Listing 1-1 into Groovy. Then we will demonstrate how to adapt the code to use common Groovy idioms.

Listing 1-1.  Simple Java Class

1.   package com.apress.bgg;
2.
3.   import java.util.List;
4.   import java.util.ArrayList;
5.
6.
7.   public class Todo {
8.          private String name;
9.          private String note;
10.
11.         public Todo() {}
12.
13.         public Todo(String name, String note) {
14.                 this.name = name;
15.                 this.note = note;
16.         }
17.
18.         public String getName() {
19.                 return name;
20.         }
21.
22.         public void setName(String name) {
23.                 this.name = name;
24.         }
25.
26.         public String getNote() {
27.                 return note;
28.         }
29.
30.         public void setNote(String note) {
31.                 this.note = note;
32.         }
33.
34.         public static void main(String[] args) {
35.                 List<Todo> todos = new ArrayList<Todo>();
36.                 todos.add(new Todo("1", "one"));
37.                  todos.add(new Todo("2", "two"));
38.                 todos.add(new Todo("3","three"));
39.
40.                 for(Todo todo : todos) {
41.                        System.out.println(todo.getName() + " " + todo.getNote());
42.                 }
43.         }
44.  }

If you have any Java experience, you will recognize Listing 1-1 as a basic Todo JavaBean. It has getters and setters for name and note attributes, as well as a convenience constructor that takes a name and note for initializing new instances. As you would expect, this class can be found in a file named Todo.java in the com.apress.bgg package. The class includes a main() method, which is required for Java classes to be executable and is the entry point into the application. On line 35, the main() method begins by creating an instance of a java.util.ArrayList to hold a collection of Todos. On lines 36–38, three Todo instances are created and added to the todos list. Finally, on lines 40–43, a for statement iterates over the collection and prints the Todo's name and note to System.out.

Converting Java to Groovy

To convert the Java Todo class in Listing 1-1 to Groovy, just rename the file to Todo.groovy. That’s right, Groovy derives its syntax from Java. This is often referred to as copy/paste compatibility. So congratulations, you are a Groovy developer (even if you didn’t know it)! This level of compatibility, along with a familiar API, helps to reduce the Groovy learning curve for Java developers. It also makes it easier to incorporate Java examples found on the Internet into a Groovy application and then refactor them to make them more Groovylike, which is what we will do with Listing 1-1.

To run this Groovy application, from the command line, type the following:

> groovy comapressggTodo.groovy

If you are coming from a Java background, you may be a little surprised that you did not need to first compile the code. Here’s the Java equivalent:

> javac comapressggTodo.java
> java com.apress.bgg.Todo

Running the Java application is a two-step process: Compile the class using javac, and then use java to run the executable class in the JVM. But Groovy will compile to byte code at runtime, saving a step in the development process and thereby increasing Groovy’s productivity. Groovy provides a lot of syntactic sugar and is able to imply more than Java. You’ll see this in action as we make our Groovy application more Groovy by applying some of the Groovy idioms.

Converting a JavaBean to a GroovyBean

Let’s begin by simplifying the JavaBean, which could also be referred to as a Plain Old Java Object (POJO). Groovy has the GroovyBean, which is a JavaBean with a simpler Groovy syntax, sometimes referred to as a Plain Old Groovy Object (POGO). GroovyBeans are publicly scoped by default. Listing 1-2 shows our example using a GroovyBean.

Listing 1-2.  Simple Example Using a GroovyBean

1.   package com.apress.bgg;
2.
3.    import java.util.List;
4.    import java.util.ArrayList;
5.
6.
7.    public class Todo {
8.
9.           String name;
10.          String note;
11.
12.           public static void main(String[] args) {
13.                   List <Todo> todos = new ArrayList<Todo>();
14.                  todos.add(new Todo(name:"1", note:"one"));
15.                  todos.add(new Todo(name:"2", note:"two"));
16.                  todos.add(new Todo(name:"3", note:"three"));
17.
18.                  for(Todo todo : todos) {
19.
20.                  System.out.println(todo.name + " " + todo.note);
21.                  }
22.          }
23.  }

Listing 1-2 is significantly shorter than Listing 1-1, primarily because Groovy has a concept of native properties, which means getters and setters do not need to be declared. By default, all class attributes—such as the name and note attributes on lines 9 and 10—are public properties and automatically generate corresponding getters and setters in the byte code. So if the class is used from Java code, or reflection is used to interrogate the class, you will see the getters and setters. These properties also have a more intuitive usage model. They can be assigned or used directly, as on line 20, where the name and note properties, rather than the getters, are used to generate the output. Also, rather than needing to explicitly create a convenience constructor for initializing a GroovyBean, you can pass named parameters in the constructor to initialize any properties you want, as in lines 14–16.

GroovyBeans have a very useful initialization feature called Named parameters. We can pass a Map to the constructor of a bean that contains the names of the properties, along with an associated initialization value. Every GroovyBean has this built-in Map constructor, which works by iterating the map object and calling the corresponding property setter for each entry in the map.

Suppose we have a GroovyBean Book, which has the properties id and title. We can initialize such bean with a map:

map = [id: 1, title: "Beginning Groovy, Grails and Griffon"]
Book = new Book( map)
We can pass the map directly to the bean:
Book = new Book ( id: 1, title: "Beginning Groovy, Grails and Griffon")

Simplifying the Code

Some of the syntax sugar included in the Groovy language is making semicolons, parentheses, and data typing optional. Other interesting features to simplify code include implicit imports like the java.util.* package, common methods like println() applying to all objects including Java objects, and more flexible strings. Listing 1-3 applies these features to our example.

Listing 1-3.  Simple Example Applying Syntactic Sugar, Implicit Imports, Common Methods,and String Features

1.   package com.apress.bgg;
2.
3.   public class Todo {
4.
5.           String name
6.           String note
7.
8.           public static void main(String[] args) {
9.                  def todos = new ArrayList()
10.                 todos.add(new Todo(name:"1", note:"one"))
11.                 todos.add(new Todo(name:"2", note:"two"))
12.                 todos.add(new Todo(name:"3", note:"three"))
13.
14.                 for(Todo todo : todos) {
15.
16.                          println "${todo.name} ${todo.note}"
17.                 }
18.          }
19.  }

In Listing 1-3, under the package declaration we no longer need to import java.util.List, java.util.ArrayList, and java.util.Iterator. These are implicitly imported since they are in the java.util.* package. Other implicitly included packages are java.lang.*, java.net.*, java.io.*, groovy.lang.*, and groovy.util.*. Also notice that, other than in the for statement (which we will clean up in the next round of refactoring), all the semicolons were removed. On line 16, we used optional parentheses with the implicit println() method. But that is not the only change to line 16. The println() method was modified to use Groovy’s GString format, which is similar to the Apache Ant property format, rather than concatenating two strings. We’ll cover Groovy strings in Chapter 2. At this point, just notice how much simpler this is to read. Line 9 has been changed to use optional typing. The variable todos is no longer typed to List. Groovy uses “duck typing,” which means if it sounds like a duck and walks like a duck, it must be a duck. Do you really care what the type of an object is, as long as you can pass it a message and it will handle the request if it can? If the object cannot handle the request, you will receive a groovy.lang.MissingMethodException or groovy.lang.MissingPropertyException. Of course, where you think typing is necessary, you always have the option of explicitly typing variables.

Using Groovy Collection Notation and Closure

The next step in refactoring the example is to take advantage of Groovy’s collection and map notation, as well as replace the ugly for statement with a more elegant closure. Listing 1-4 shows this version.

Listing 1-4.  Example with the Groovy Collection Notation and Closure

1.   package com.apress.bgg;
2.
3.   public class Todo {
4.
5.          String name
6.          String note
7.
8.          public static void main(String[] args) {

9.                 def todos = [
10.                      new Todo(name:"1", note:"one"),
11.                      new Todo(name:"2", note:"two"),
12.                      new Todo(name:"3", note:"three")
13.                ]
14.
15.                todos.each {
16.                      println "${it.name} ${it.note}"
17.                }
18.         }
19.  }

Notice how the ArrayList was replaced with []. Again, this is just syntactic sugar; Groovy really is instantiating an ArrayList. Similarly, we can create maps with the [:] syntax. To make the code more clean, we can initialize the list without needing to call the add() method for each entry. Then to simplify the iteration, we call the each() method, passing a closure that prints out the string. Notice that, by default, the iteration variable is it. Chapter 2 will provide more explanations and examples of Groovy lists, maps, and closures.

Getting Rid of main()

One bit of Java ugliness left in our example is the main() method. After all these improvements, the main() method now stands out. Fortunately, Groovy has a concept of scripts as well as classes, and we can turn this into a script, removing the need for the main() method. To begin, the file must be renamed to something like Todos.groovy. This is because a script will also be compiled to a class, and if we didn’t change the name, there would be a name clash between the Todo class and the Todo script. Then we simply move the code that currently exists in the main() method outside the Todo class. Note that, in Groovy, any code that is not inside a class is called a script. When the script is run, it will behave the same as before. Listing 1-5 shows the script version.

Listing 1-5.  Example as a Script

1.   package com.apress.bgg;
2.   public class Todo {
3.   String name
4.   String note
5.   }
6.   def todos = [
7.   new Todo(name:"1", note:"one"),
8.   new Todo(name:"2", note:"two"),
9.   new Todo(name:"3", note:"three")
10.  ]
11.  todos.each {
12.  println "${it.name} ${it.note}"
13.  }

Finally, we have elegant, easy-to-read code at a fraction of what we started with in Java. It should be obvious that if we had started with the Groovy idioms to begin with, the Groovy approach would have been much more productive.

Groovy Language Key Features

This section gives a general overview of the language features that make Groovy a commendable extension to the Java platform. A detailed treatment of all these features is given in subsequent chapters.

Assertion

An assertion is used to validate that an expected condition is true. Assertions in Groovy are more powerful than in Java because assertion in Java works only on Boolean, whereas assertion in Groovy can accept any type. Assertions in Java can be disabled, whereas assertions in Groovy are always executed and are recommended to be used in the production code.

Listing 1-6.  Assertion Example

def list = [1, 2, 'x'] // list of 3 elements
assert list.size() == 3

Annotations for AST Transformation

When the Groovy compiler compiles Groovy scripts and classes, the Groovy parser (the front end of the compiler) creates an Abstract Syntax Tree (AST) before generating the final byte code for the class. The AST is the in-memory representation of the source code, comprising class, method, property, statement, and variables. AST transformation is the capability to add new code (methods, checks) into source code before the final byte code is generated. The objective of the AST transformation is to let developers structure their code while focusing more on the business code rather than on boilerplate code or cross-cutting concerns. Groovy provides annotations you can use to annotate code structures for AST transformation. Here is one example of AST transformation using @Singleton annotation provided by Groovy:

Listing 1-7.  Using Annotations for AST Transformation

@Singleton
class SomeSingleton
{
//..
}

The @Singleton annotation creates a private constructor and a static method, which gives us an instance of the Singleton through AST transformations.

Builder

Generating the simplest XML document in Java is enormously difficult and time consuming. Groovy simplifies generating XML by providing built-in builder classes that make it possible to build a tree-like structure from within the code itself. That is, the structure of the code itself resembles the tree-like structure we are trying to build, thus making the task of generating tree-like structure painless.

Listing 1-8.  Tree-like Structure in XML

<employee>
<name>John Doe</name>
<gender>male</gender>
</ employee >

Listing 1-9.  Groovy Code to Generate Preceding Tree-like Structure

def builder = new groovy.xml.MarkupBuilder()
builder.employee {
name   'John Doe'
gender  'male'
}

Closure

A Groovy closure is a block of reusable code within curly braces {}, which can be assigned to a property or variable, or passed as a parameter to a method. The code within the curly braces is executed when the closure is invoked.

Listing 1-10.  Using Closure

def name = "Chris"
def printClosure = { println "Hello, ${name}" }
printClosure()
name = "Joseph"
printClosure()

Here is the output:

Hello, Chris
Hello, Joseph

GDK

Groovy as a whole comprises Groovy language, libraries specific to Groovy-specific libraries, and GDK. The GDK is Groovy’s extension to some of the existing classes in the JDK. You can access the full API specification at http://groovy.codehaus.org/groovy-jdk.

Metaprogramming

Metaprogramming means writing a program that creates, queries, and manipulates other programs or (more often) itself. Metaprogramming can occur at either compile-time or runtime.

The covenant of compile-time metaprogramming is byte-code generation. In Groovy, compile-time metaprogramming lets you modify the AST before generating final byte code. We illustrated an example of compile-time metaprogramming in the “Annotations for AST Transformation” section. Runtime metaprogramming is centered on enabling dynamic method-invocation and synthesis of methods and classes. In Groovy, runtime metaprogramming is realized using meta-object protocol. The MOP, in Groovy, comprises categories, expandos, and metaclasses.

Listing 1-11.  Runtime Metaprogramming

String.metaClass.firstUpper = {−>

    return delegate[0].toUpperCase() + delegate[1..delegate.length() - 1]
}

println "iiii".firstUpper()

Listing 1-11 shows how you can add an additional method to a class on the fly. We added an additional method to String class, which is immutable.

Here is the output:

Iiii

Native JSON Support

JSON (JavaScript Object Notation) is a lightweight data interchange format, used as an alternative to XML for serializing and transmitting structured data over a network.

As a simple example, data about an employee can be written in JSON as follows:

Listing 1-12.  Example of JSON

var person= {
          "name" : "John Doe",
          "age" : "40"
};

This creates an object that can be accessed using the employee variable. Groovy 1.8 introduced native JSON support through JsonSlurper for reading JSON and JsonBuilder for writing JSON.

Listing 1-13.  Reading JSON

import groovy.json.JsonSlurper
 def slurper = new JsonSlurper()
 def result = slurper.parseText('{"person":{"name":"John Doe","age":40,"cars":["bmw","ford"]}}')

 println result.person.name
 println result.person.age
 println result.person.cars.size()
 println result.person.cars[0]
 println result.person.cars[1]

Here is the output

John Doe
40
2
bmw
ford

Native Support for Lists and Maps

Java has no language-level support for collections that it has for arrays. Groovy enhanced the Java collection classes by adding and improving the declaration syntax and additional methods.

Groovy contains first-class constructs for List and Map. It also adds the new collection type—Range—at the language level, which provides special-purpose syntax for managing ranges of values.

Listing 1-14.  Support for Lists as a Language Feature

authors = [ 'Vishal', 'Chris', 'Joseph', 'Jim' ]
println authors
println authors[0]

Here is the output:

["Vishal", "Chris", "Joseph", "Jim"]
Vishal

Native Support for Regular Expression

Groovy builds regular expression handling right into the language via the =∼ operator and matcher objects.

Object Orientation: Everything is an Object in Groovy

Unlike Java, everything in Groovy is an object; there are no primitive types. As a result, in Groovy, no auto boxing is needed because everything is an object.

For example, Groovy executes 2 + 2 as 2.plus(2). The plus operator is implemented via the plus() method. In Groovy, all operators are method calls. This makes it possible to apply object-orientation to operators; for example, it is possible to overload/override any operator to give a new implementation.

String interpolation

String interpolation is the ability to substitute an expression or variable within a string. Java doesn’t support string interpolation. You must manually concatenate the values. Here is an example of the type of code you need to write in Java:

Listing 1-15.  String Concatenation in Java

String lastName= "Layka";
String fullname= "Vishal " + lastName;
System.out.println(fullname);

Listing 1-16.  String Interpolation in Groovy

def lastName = "Layka"
def fullname = "Vishal ${lastName} " // string interpolation (also called Gstring)
println fullname

Static and Dynamic Typing

Groovy supports both static and dynamic typing when declaring variables. Dynamic typing can be achieved by using the def keyword.

Listing 1-17.  Dynamic and Optional Typing in Groovy

def var = 10
var = "It's a String"

The def keyword is optional in scripts.

Listing 1-18.  Static and Optional Typing in Groovy

String  s1 = " A String " // static
s2 = "Another String " // optional typing :type is left to be determined at the time of assignment.

Static Type Checking

Groovy 2.0 introduces a @TypeChecked annotation, which annotates a method or a class that needs to be static type checked. This type-checked mode, enabled through annotation, indicates the errors at compile time.

The static type checker is built using Groovy’s existing powerful AST transformation mechanisms. Being an optional feature, you are not forced to use it if you don’t need it. To trigger static type checking, just use the @TypeChecked annotation on a method or on a class to turn on checking.

Listing 1-19.  Using TypeChecked Annotation

import groovy.transform.TypeChecked

void doIt() {}

@TypeChecked
void test() {
    
    dott ()//compilation error:cannot find matching method dott()

}Figure 1-1 illustrates the @Typechecked annotation in action in Eclipse.

9781430248064_Fig01-01.jpg

Figure 1-1 .  Using the @TypeChecked annotation

Static Compilation

Groovy 2.0 also makes it possible to enable static compilation via @CompileStatic. This mode eliminates the runtime overhead of dynamic dispatch.

Listing 1-20.  Using CompileStatic Annotation

import groovy.transform.CompileStatic

@CompileStatic
int doubleIt(int num) {
    2* num
}

assert doubleIt(2) == 4

Using @CompileStatic will statically compile the code, and the generated byte code will run just as fast as java’s byte code. Like the @TypeChecked annotation, @CompileStatic can annotate classes and methods, and @CompileStatic(SKIP) can bypass static compilation for a specific method when its class is marked with @CompileStatic.

Optional Syntax

Now let’s look at the optional syntax.

Access Modifiers

In Groovy, classes without an access modifier are considered public. Attributes without an access modifier are considered private. Methods without an access modifier are public. This is in contrast with Java, where methods and fields default to package access. The reason Groovy chose to make the public access modifier the default is that it is the most frequently used modifier, whereas package access is used far less frequently.

Checked Exceptions

In Groovy, checked exceptions need not be declared or caught, as Groovy automatically wraps exceptions as a RuntimeException.

Getters and Setters

Similar to JavaBeans, Groovy introduces GroovyBeans, which support the notion of properties. Properties in GroovyBeans look just like public fields, with no need to define explicit getters and setters.

Listing 1-21.  Properties in Groovy

class Employee{
String name
}
Employee emp = new Employee()
emp.setName("John Doe" )

println emp.name

Import Statements

By default, Groovy always imports the following packages:

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

Parentheses and Semicolons

Parentheses and semicolons are optional in Groovy. The following statements are valid in Groovy:

Listing 1-22.  Optional Semicolons and Parentheses

println ("hello");
println "hello"

Return Type and the return Keyword

In Groovy, the return type for a method and the return keyword as the last statement in the method are optional. The result value of the last statement is always returned from a method call.

Listing 1-23.  Optional return Keyword

String greeting() {
result = "Hello world"
result
}
println greeting()

Listing 1-23 shows that return keyword is optional.

If the def keyword is used as a return type, Groovy dynamically figures out the return type during runtime depending on the value returned.

Listing 1-24.  Optional Return Type

def greeting() {
result = "Hello world"
result
}
println greeting()

Listing 1-24 shows that Return type is dynamic.

In both Listing 1-23 and Listing 1-24, the output is

Hello world

image Note  It appears that removing constructs like parentheses and semicolons is unessential and rather mundane, but as you will see in domain-specific languages, one of the key areas of Groovy, removing these constructs brings code close to the natural language.

Summary

The purpose of this chapter was to provide a preview of some key features of Groovy. We demonstrated how you can dramatically reduce the code it takes to write the equivalent Java class in Groovy, while increasing the readability and expressiveness. In the next chapter, we will continue exploring Groovy by looking at its basic language features.

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

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