- •Credits
- •About the Authors
- •About the Reviewers
- •www.PacktPub.com
- •Table of Contents
- •Preface
- •Introduction
- •Installing Groovy on Windows
- •Installing Groovy on Linux and OS X
- •Executing Groovy code from the command line
- •Using Groovy as a command-line text file editor
- •Running Groovy with invokedynamic support
- •Building Groovy from source
- •Managing multiple Groovy installations on Linux
- •Using groovysh to try out Groovy commands
- •Starting groovyConsole to execute Groovy snippets
- •Configuring Groovy in Eclipse
- •Configuring Groovy in IntelliJ IDEA
- •Introduction
- •Using Java classes from Groovy
- •Embedding Groovy into Java
- •Compiling Groovy code
- •Generating documentation for Groovy code
- •Introduction
- •Searching strings with regular expressions
- •Writing less verbose Java Beans with Groovy Beans
- •Inheriting constructors in Groovy classes
- •Defining code as data in Groovy
- •Defining data structures as code in Groovy
- •Implementing multiple inheritance in Groovy
- •Defining type-checking rules for dynamic code
- •Adding automatic logging to Groovy classes
- •Introduction
- •Reading from a file
- •Reading a text file line by line
- •Processing every word in a text file
- •Writing to a file
- •Replacing tabs with spaces in a text file
- •Deleting a file or directory
- •Walking through a directory recursively
- •Searching for files
- •Changing file attributes on Windows
- •Reading data from a ZIP file
- •Reading an Excel file
- •Extracting data from a PDF
- •Introduction
- •Reading XML using XmlSlurper
- •Reading XML using XmlParser
- •Reading XML content with namespaces
- •Searching in XML with GPath
- •Searching in XML with XPath
- •Constructing XML content
- •Modifying XML content
- •Sorting XML nodes
- •Serializing Groovy Beans to XML
- •Introduction
- •Parsing JSON messages with JsonSlurper
- •Constructing JSON messages with JsonBuilder
- •Modifying JSON messages
- •Validating JSON messages
- •Converting JSON message to XML
- •Converting JSON message to Groovy Bean
- •Using JSON to configure your scripts
- •Introduction
- •Creating a database table
- •Connecting to an SQL database
- •Modifying data in an SQL database
- •Calling a stored procedure
- •Reading BLOB/CLOB from a database
- •Building a simple ORM framework
- •Using Groovy to access Redis
- •Using Groovy to access MongoDB
- •Using Groovy to access Apache Cassandra
- •Introduction
- •Downloading content from the Internet
- •Executing an HTTP GET request
- •Executing an HTTP POST request
- •Constructing and modifying complex URLs
- •Issuing a REST request and parsing a response
- •Issuing a SOAP request and parsing a response
- •Consuming RSS and Atom feeds
- •Using basic authentication for web service security
- •Using OAuth for web service security
- •Introduction
- •Querying methods and properties
- •Dynamically extending classes with new methods
- •Overriding methods dynamically
- •Adding performance logging to methods
- •Adding transparent imports to a script
- •DSL for executing commands over SSH
- •DSL for generating reports from logfiles
- •Introduction
- •Processing collections concurrently
- •Downloading files concurrently
- •Splitting a large task into smaller parallel jobs
- •Running tasks in parallel and asynchronously
- •Using actors to build message-based concurrency
- •Using STM to atomically update fields
- •Using dataflow variables for lazy evaluation
- •Index
Using Groovy Language Features
If a class already implements Serializable, the @AutoClone annotation can be configured to use the Serialization style. This feature performs a deep copy
automatically, attempting to copy the entire tree of objects including array and list elements. The AutoCloneStyle.SERIALIZATION style has some limitations; it is generally slower and it doesn't support fields marked with final.
Defining code as data in Groovy
One of the things that attracted the Java crowd to Groovy has been the presence of closures in the language since its creation in 2003. Closures are a very powerful feature of Groovy
and one of the most widely used. It is important to understand them well to take full advantage of the language. In this recipe, we will try to demonstrate the beauty that closures add to the language.
Getting ready
At its core, a closure is an anonymous block of code, such as:
{ -> }
The previous snippet is actually a closure without body. It is, in fact, an object of type groovy.lang.Closure. As with every other object, a closure can be passed to other methods or even to other closures. However, a closure is also a method—a method with no associated class; therefore, it may have arguments and can return a value (yes, it can also return a closure). A closure always returns the value of the last statement in the body; the return keyword is not needed. The body of a closure is not executed until it gets called.
This is what a closure definition with an argument looks like:
def doubling = { arg1 -> println arg1 * 2 }
This closure just prints the doubled value of the argument. The closure is assigned to the variable doubling. The argument is not typed, and it gets used in the body of the closure, the statement after the -> symbol. The closure object can be passed to other methods as a parameter. For example, if we try to print it, we will actually call the toString method of the
Closure class:
println doubling
The previous line of code will yield something like the following:
closures$_run_closure1@76bb5e95
We can also pass closures to many methods (for example, each, collect, find, and so on) that Groovy makes available on collections and arrays:
[1,2,3,4].each(doubling)
104
www.it-ebooks.info
Chapter 3
The preceding code snippet will apply the passed closure to every element in the collection:
2
4
6
8
Now that we have a general idea about closures, we can look at how to use them to write more elegant and concise code. Closures normally contain less code, have little or no repetition, and can be re-used easily . This is because a closure can also be defined code as data.
How to do it...
A common way to display the conciseness of Groovy closures is to show some looping and iteration methods from the Groovy Collection API:
[1,2,3].each { println it }
The previous snippet is a great example of the power of closures. The code prints all the elements of a list by iterating on each element of the array, and calls the println command on each element. The astute reader is probably wondering what the it keyword is for; it is simply a reference to the current element. The snippet can be also expressed in a slightly more verbose way if we choose not to use it:
[1,2,3].each { element -> println element }
The it keyword is an implicit variable that works on closures, accepting a single argument. A very welcome syntactic sugar!
The each is a method from the enhanced java.lang.Object of the Groovy JDK and takes a closure a parameter. The closure contains the code that does actual stuff on each member of the list.
The Java equivalent of the former snippet would look as follows:
List<Integer> list = Arrays.asList(1,2,3); for (Integer it :list) {
System.out.println(it);
}
Another example of how a closure can help with refactoring the code is that it deals with resources that have to be disposed of once out of scope.
105
www.it-ebooks.info
Using Groovy Language Features
Let's create a class, ExpensiveResource, and assume that this resource has to be explicitly opened and closed once it has been used (very much like a JDBC connection):
class ExpensiveResource {
def open() { println 'opened!' }
def writeData(data) { println "data written! $data" } def close(){ println 'closed!'}
}
To use this class, we would write something like the following:
def e = new ExpensiveResource() try {
e.open() println e.data
}finally { e.close()
}
The open and close methods must be called every time we deal with the resource. Let's see how a closure simplifies and makes the code more polished:
def safeResource(Closure closure) {
def resource = new ExpensiveResource() try {
resource.open()
closure(resource)
}finally { resource?.close()
}
}
safeResource { it -> it.writeData('hello world!') }
The method safeResource accepts a closure and encapsulates the resource management code, leaving the calling code to show its intent much more clearly.
Groovy provides a similar approach when dealing with file access by automatically handling resource management code such as opening, closing, and handling exceptions behind the scenes. For instance, the method file.eachLineMatch(pattern) { ... } opens
a file, iterates over each line trying to find the lines that match the specified pattern, and then invokes some code passed in form of a closure for the matching line(s), if any, before eventually closing the file.
106
www.it-ebooks.info
Chapter 3
There's more...
Once you get familiar with Groovy closures, it will not take long before you'll encounter the need to curry your closures. The term currying comes from the functional programming domain, and it defines a way to apply default values to a closure by defining a complete new closure. Here is an example:
def multiply = { x, y -> x * y } multiply 3, 5
Result: 15
def closureByFour = multiply.curry(4)
The previous code snippets shows a standard closure that multiplies two numbers and returns the result (remember, no return is needed). The second closure calls the curry method on the first closure and specifies the value 4. The second closure, closureByFour, can then be invoked with one argument only, and that argument will be multiplied by 4, the value passed to the curry method. The limitation of the curry method is that arguments are bound from left to right in the argument list. In other words, in two arguments-closures, only the left argument can be used with the curry function.
The following example shows an interesting use case for currying. Let's define a closure that filters the elements of a list. The filter argument is a closure:
def filterList = { filter, list -> list.findAll(filter) }
Now let's define a couple of closures that can be used as filters:
def even = { it % 2 == 0 } def odd = { !even(it) }
Finally, we create two new closures by applying the curry function to the original closure, and passing one of the closure filters:
def evenFilterList = filterList.curry(even) def oddFilterList = filterList.curry(odd)
The new closures can now be invoked autonomously to filter out odd and even numbers:
assert [0,2,4,6,8] == evenFilterList(0..8) assert [1,3,5,7] == oddFilterList(0..8)
107
www.it-ebooks.info