ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Java Cookbook, 2nd Edition

Groovy, Java's New Scripting Language

by Ian F. Darwin, author of Java Cookbook, 2nd Edition
09/29/2004

When some Java developers hear about Groovy, their first reaction often is, as mine was, "Oh, no, not another scripting language for Java." We already have, after all, JavaScript and Rhino, Jython, Jelly, BeanShell, JRuby, Tcl/Java, Sleep, ObjectScript, Pnuts, Judoscript, the Bean Scripting Framework (BSF)--which gives access to Perl, TK/Tcl, and more--and many others. But other developers have been hoping for a scripting language with the power of Perl, Python, or Ruby but without having to re-learn everything from the ground up. Whichever camp you're in, I hope to show you enough of Groovy in this article that you will be interested to try it and judge for yourself.

Why Groovy?

Why would Bob McWhirter and James Strachan create a new scripting language? Why would they call it Groovy? More importantly, what features would enable Groovy to succeed when others are already entrenched? Let's answer the third question with a look at Groovy's features.

When scripting languages that started elsewhere come to Java, they tend to bring a lot of their own API with them rather than using the "standard" (to us) Java API. Groovy is not guilty here--it provides very little special-purpose API; the entirety of the standard Java API is given to you in Groovy as it is in Java, and any third-party Java can be made available just by putting it in your CLASSPATH.

Quoting the Groovy FAQ:

Think of Groovy as a Ruby- or Python-like language that is tightly integrated with the Java platform (as opposed to the Unix/Posix command shell and C-libraries), allowing you the same powerful and concise coding syntax as Ruby or Python, but allowing you to stay on the JVM and protect your investment in J2SE, J2EE, and all the plethora of great useful Java code out there without any adapter layers or parallel API sets ...

Foreign scripting languages tend to have their own special syntax, based on what the original developers liked. Groovy is peachy here, too, because its syntax is based on Java's, with just a spoonful of syntactic sugar to help the medicine go down. For example, instead of having to write:

value = object.getItemCount();

you can just write:

value = object.itemCount

In other words, objects in Groovy are treated as JavaBeans, and setters/getters result in accessible properties. Because Groovy is generally much less restrictive than Java about declarations, most variables in Java can be assigned without declaring them, although at present you can't use the += operator on something that doesn't have a value.

In fact, you can create bean classes in Groovy without having to write accessors, as shown in the person.groovy example below. Groovy statements don't need to have a class statement and named methods if they are self-contained; but if you want to define one or more classes you can, and classes can have method definitions.

Example 1. person.groovy

class Person {
	firstName
	lastName
	address1
	city
	province
	postcode
}

p = new Person(firstName:'Ian', lastName:'Darwin', province:'Ontario')

println "Hello ${p.firstName} ${p.lastName}"

Related Reading

Java Cookbook
By Ian F. Darwin

Another bit of syntactic sugar is that semicolons are optional at the end of statements. You may, as I do, put them in out of habit and because it's easier to be consistent. But the Groovy language isn't Java, and if you want to leave off your semicolons, you can. And before you start denigrating "syntactic sugar," remember that J2SE 1.5 ("Java 5") provides auto-boxing and auto-unboxing, which automatically converts between primitives like ints and, whenever needed, their object-wrapper equivalents (like Integer). (Chapter 8 of my book, Java Cookbook, 2nd Edition, covers this and other new-in-1.5 features such as Generics; you can download this chapter from the book's catalog page.)

A third problem with some scripting languages has been performance, though this has become less of an issue as computers get faster. Somebody once wrote that software expands to use up all available increases in computing resources, and that doesn't seem far off the mark when you look at modern commercial operating systems and applications. Groovy wins here, too, because Groovy scripts can be compiled into .class files. These files are indistinguishable from those produced by javac or an IDE, and can therefore take advantage of speed improvements in, for example, Sun's HotSpot optimizing-Just-In-Time JVM.

Well, indistinguishable syntactically; they are well-formed Java bytecode files. That does not mean that you can compile any Groovy script into a standalone Java program--the Groovy runtime is required on your classpath, both to compile the Java code that uses Groovy, and to find the Java classes of the Groovy runtime. I'll give an example later.

Finally, some scripting languages tend to have ambiguous documentation, or multiple implementations (Jython versus Python, for example). Groovy again wins here--its language has a Java Standards Request, or JSR 241, that includes a precise Groovy Language Specification (GLS). The specification co-lead and main author of the GLS is Richard Monson-Haefel, well known as the author of the O'Reilly book Enterprise JavaBeans and member of the EJB2 JSR experts group. Richard is also the only person I know who wrote an entire EJB server for fun, and gave it away as open source. (He's also the original author of OpenEJB, which has been incorporated into Apple's WebObjects and Apache Geronimo.)

Why Use Groovy?

So, it's groovy that Groovy doesn't suffer from the problems above, but what is it actually good for? Well, any kind of scripting, really. People are starting to use it for prototyping; that is, get an algorithm working in Groovy, then convert it to Java. But often you can just write something in Groovy and keep it as a Groovy script. Just to give you one example, see the fixid.groovy example below, a script I wrote to ensure that all of the Java files in a project have a CVS ID string.

Example 2. fixid.groovy

# Make sure all the Java files in a collection have a CVS ID String.
# Don't apply to all files because it may damage binary files.

new java.io.File(".").eachFileRecurse({file | if (file.name.endsWith(".java")) {
   old = file.getText()
      if (!old.contains("$Id")) {
         println "Fixing file ${file.name}"
         out = file.newPrintWriter()
         out.println("// Next line added by fixid script; 
                     should move into doc comment")
         out.println("// $I"+"d$")   // + to hide from CVS
         out.print(old)
         out.close()
     }
  }
})

Getting Started

The only good way to learn a language (even a scripting variant of a language you know) is to download it and start applying it. (It's also a good idea to review the installation notes page.) And, if you don't want to type in my code examples, you can download them here.

You need JDK 1.4 or later; Groovy will not run on 1.3. When you unpack the archive, you should wind up with these subdirectories:

To use Groovy, all you need to do is set GROOVY_HOME (and JAVA_HOME, but you probably have that set already). And you probably want to put GROOVY_HOME/bin onto your program path. For example, on my Mac with the Unix Korn shell, I have lines like these in my .profile:

export JAVA_HOME=/Library/Java/Home
export GROOVY_HOME=/home/ian/groovy
PATH=$PATH:$GROOVY_HOME/bin

There are several ways to invoke Groovy interactively. The groovysh terminal-based interpreter and the groovyConsole GUI interpreter let you try your hand at composing Groovy interactively. Using the present version (Beta 0.6.1) of groovysh consists of typing one or more Groovy statements, then typing "go" or "execute" to run them (though this is labelled as a "temporary command"). Here's an example of groovysh in action:

Example 3. groovysh

ian:61$ groovysh
Lets get Groovy!
================
Version: 1.0-beta-6 JVM: 1.4.2-38
Type 'exit' to terminate the shell
Type 'help' for command help

1> meaning = 42
2> println "Hello. Did you know that all it means is ${meaning}?"
3> go
Hello. Did you know that all it means is 42?

1> exit
ian:62$ 

Using the groovyConsole consists of typing Groovy statements in the bottom panel, then invoking the Action -> Run menu item and looking in the top panel for messages and the invoking console for standard output (Ctrl-R is the keyboard shortcut for Run). groovyConsole has the advantage that you can save a script file from its File menu. Here's an example of groovyConsole in action:

groovyConsole

groovyConsole

As well, the groovy command runs a set of Groovy statements entered on the command line (with -e), or stored in a text file whose name is given on the command.

groovy -e 'System.in.readLines().each { println it }'

This makes a simple "line count" program, for example:

ian$ ls | groovy -e 'c=0; System.in.readLines().each { ++c };println c'  
6
ian$

At least on Unix/Linux/BSD/Mac OS X, you need to put single quotes around the entire command to protect all "meta-characters" in it. Which you use is a matter of choice.

There are also Groovy plugins for popular IDEs, including Eclipse, IntelliJ, IDea (but its page is blank), and even vim. There is not yet support for Emacs or NetBeans, as far as I can tell. But given Groovy's similarity to Java, both of these should soon follow. And, once the JSR is a bit further along, I'd expect to see the commercial IDEs catching up.

Groovy Is Not Java

Groovy provides some syntax extensions beyond standard Java. One of the most interesting is what are called closures. This term has been overloaded in a lot of places in computer science, but for now just think of Groovy closures as being similar to anonymous inner classes. One difference is that variables can be passed in or out; Groovy closures do not constitute a "lexical scope" the way an inner class does. The example below, closures.groovy, shows how to break a String into a List and print it one word per line, both the "long way" and using closures.

Example 4. closures.groovy

# without closures
x = "When in the course of human events ...".tokenize()
for (val in x) println val

# with closures
"When in the course of human events ...".tokenize().each { val | println val }

# with closures, default parameter name
"When in the course of human events ...".tokenize().each { println it }

The closure code is used to print each value of the list. In the first version, a parameter, val, is declared (before the |), and used in the body. In the second version, I use Groovy's default parameter name it (presumably short for "item").

Another interesting syntax enhancement is the use of variable substitution within strings. Almost any String assignment can contain the pattern ${variablename}, and the value of the named variable will be interpolated into the String. This is a much more convenient form than Java's extensive use of the + operator for string concatenation. This can be used in printing, as in this hello.groovy example:

Example 5. hello.groovy and date.groovy

i = 42
println "Hello ${i}"

This prints "Hello 42". The interpolated value can be a property, as shown in date.groovy:

i = new java.util.Date();
println "Today is day ${i.day} of month ${i.month}"

I said that Groovy doesn't bring a lot of new API. But it does offer a lot of convenience methods added onto the standard API. For example, the Groovy version of String adds the tokenize() method used in the closure.groovy example above. The file docs/groovy-jdk.html in the Groovy distribution lists all of the methods added to the JDK classes; it's quite an extensive list, and adds up to a great deal of time saved when using Groovy compared to using "raw Java."

As another example, Groovy's java.io.File class has a newReader method that returns a BufferedReader (and newPrintWriter(), which returns a PrintWriter). java.io.File also has eachLine, which opens the file and reads each line for you; now that's high-level! The example below is wc.groovy, my implementation of wc, a traditional Unix tool that counts the lines, words, and characters in a text file:

Example 6. wc.groovy

# simple implementation of Unix "wc" in groovy.
# could simplify with File.splitEachLine() but this way gets "chars" right.
filename=args[0]
chars=0; lines=0; words=0;
new java.io.File(filename).eachLine {
	chars+=it.length() + 1
	words+=it.tokenize().size();
	lines++;
}
println "\t${lines}\t${words}\t${chars}\t${filename}"

Running the script produces output that is close to the original:

Example 7. wc.groovy versus the original

ian:136$ wc test.txt
       2      25     130 test.txt
ian:137$ groovy wc.groovy test.txt
        2       25      130     test.txt
ian:138$ 

Groovy also adds several convenience methods for lists and maps; some of these are shown in the lists.groovy example below:

Example 8. lists.groovy

# List operations
list = ["ian","brian","brain"]
println list;
println "Maximum value: ${list.max()}"

# inject is like an iterator with carryover of last value
list.inject("foo", { val, elem|println "${val} -- ${elem}"; return elem })
# findAll returns all the elements for which the closure returns true.
println "findAll: "+list.findAll({it.contains("ian")})

# Ruby-style ranges, +- operators, etc.
validCardYears = 2004..2008
validCardYears.each {println "Valid year: ${it}"}
lastValidCardYear = validCardYears[-1]
println "Last valid year is currently ${lastValidCardYear}"

Running this catch-all script produces the following output.

groovy src/lists.groovy
[ian, brian, brain]
Maximum value: ian
foo -- ian
ian -- brian
brian -- brain
findAll: [ian, brian]
Valid year: 2004
Valid year: 2005
Valid year: 2006
Valid year: 2007
Valid year: 2008
Last valid year is currently 2008

Finally, just to prove it can be done, I back-ported wc.groovy into Java; the WC.java example gives the right answer, but has roughly twice the amount of code.

Example 9. WC.java

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;

/** simple implementation of unix "wc" in Java. */
public class WC {
	public static void main(String[] args) throws IOException {
		int chars=0, lines=0, words=0;
		String filename=args[0];
		BufferedReader r = new BufferedReader(new FileReader(filename));
		String it;
		while ((it = r.readLine()) != null) {
			chars+=it.length() + 1;
			words+=new StringTokenizer(it).countTokens();
			lines++;
		}
		System.out.println("\t" + lines + "\t" + words + 
			"\t" + chars + "\t" + filename);
	}
}

XML, Swing, Builder, and All That

Groovy includes a tree-based markup generator called GroovyMarkup that can be subclassed to make a variety of tree-based object representations, including XML markup, HTML markup, SAX event firing, and even Swing user interfaces! The example below, swingbuilder.groovy, shows a user interface with a variety of labels and text fields built from a list, a pop-up "About" box, and two ways of exiting: a push button or just closing the main window (since defaultCloseOperation is set to EXIT_ON_CLOSE).

Example 10. swingbuilder.groovy

import groovy.swing.SwingBuilder;

theMap = ["color":"green", "object":"pencil", "location":"home"];

// create a JFrame with a label and text field for each key in the Map
swing = new SwingBuilder();
frame = swing.frame(title:'A Groovy Swing', location:[240,240],
	defaultCloseOperation:javax.swing.WindowConstants.EXIT_ON_CLOSE) {
	panel() {
		for (entry in theMap) {
			label(text:entry.key)
			textField(text:entry.value)
		}
		button(text:'About', actionPerformed:{ 
			pane = swing.optionPane(message:'SwingBuilder Demo v0.0')
			dialog = pane.createDialog(null, 'About')
			dialog.show()
		})
		button(text:'Quit', actionPerformed:{ System.exit(0) });
	}
}
frame.pack();
frame.show();

There are no actions yet for the text fields, so changing them doesn't actually do anything. A more elaborate Swing demo, and other demos, can be found at the Groovy web site.

Here's how it looks in action:

swing demo

Servlet Support

Another interesting API that Groovy supports is the J2EE servlet API. Like standard JSPs, GroovyServlet provides an out object that is used here. The handleform.groovy example below is a simple GroovyServlet in action that receives the content of a simple HTML form (with name, address, phone number, and the like) and stores the fields' contents into a JavaBean, which is then persisted using an already written data accessor.

Example 11. handleform.groovy

import java.util.Date
import beans.Person
import beans.PersonDAO

bean = new Person();

bean.firstName = ${firstName}
// etc for other properties

out.println(<<<EOS
<html>
<head>
	<title>Thanks for Signing Up Via the Groovy Servlet</title>
</head>
<body>
The Groovy Servlet thanks you, 
${firstName} at ${request.remoteHost}, 
for signing up with us at ${new Date()}.
<hr/>
</body>
</html>
EOS)
out.println("Bean = " + bean);
new PersonDAO().insert(bean);
out.println("<hr>");
out.println("(database updated)");

This example also shows use of the here document, an idea borrowed from the Bourne shell and its many derivatives on Unix. Everything from the line following the <<< up to the string that ends that line is copied, in this case to the argument of the out.println(), which causes the whole mess of HTML--after the substitution of ${firstName} and so on--back to the user's browser.

GroovyServlet does not pretend to be a full MVC framework like Struts or JSF, but it is good for some servlet tasks. To make the above Groovy script, one only needs a servlet and servlet-mapping elements in the web.xml file, and two .jar files, groovy.jar and asm.jar, from the distribution.

Read more about GroovyServlet at the Groovy Servlets page.

Mix and Match

How about using Groovy from within Java? There are several ways.

You can use groovyc just like javac to produce bytecode files. Suppose I have this complicated Groovy script, g.groovy:

Example 12. g.groovy

i = 42
println "Hello ${i}"

The command to run this as a script is groovy g.groovy, which produces this output:

Hello 42

Now to compile it to bytecode, I just say groovyc g.groovy. Then I can call it from within a Java class. For example:

public class j {
	public static void main(String args[]) {
		new g().run();
	}
}

Then I can compile and run class j using normal javac and java, remembering to include the Groovy .jar and its helper, asm.jar, in my classpath (I know there are better ways of doing so than shown, but I chose the most transparent one here for readers trying it out by hand):

$ javac -classpath /home/ian/groovy/lib/groovy-1.0-beta-6.jar:/home/ian/groovy/lib/asm-1.4.1.jar:. j.java
$ java -classpath /home/ian/groovy/lib/groovy-1.0-beta-6.jar:/home/ian/groovy/lib/asm-1.4.1.jar:. j
Hello 42
$ 

What's Next?

There is far more to Groovy than I have room to explain in this article. If you're a Java developer and you're not already a raving fan of Jython, PNuts, or any of the other Java-related scripting languages, I urge you to download Groovy and give it a try. Even if you prefer one of those other scripting languages, check out Groovy--you might like it.

Because Groovy is new, there is still a lot to be done. The Groovy developers are always looking for help.

Groovy needs to do a better job of error handling. The groovysh interpreter prints a caught exception, and the Groovy runtime prints a stack trace. But most exceptions are the result of user error, and it would be good if Groovy could report on such errors a little better.

As Groovy continues to mature, expect to see more and more about it in the Java media, and more developers using it for scripting tasks.

Ian F. Darwin has worked in the computer industry for three decades: with Unix since 1980, Java since 1995, and OpenBSD since 1998. He is the author of two O'Reilly books, Checking C Programs with lint and Java Cookbook, and co-author of Tomcat: The Definitive Guide with Jason Brittain.


In June 2004, O'Reilly Media released Java Cookbook, 2nd Edition.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.