
- •brief contents
- •contents
- •foreword
- •preface
- •acknowledgments
- •about this book
- •Roadmap
- •Code conventions and downloads
- •Author Online
- •About the author
- •about the cover illustration
- •1 Why add Groovy to Java?
- •1.1 Issues with Java
- •1.1.1 Is static typing a bug or a feature?
- •1.1.2 Methods must be in a class, even if you don’t need or want one
- •1.1.3 Java is overly verbose
- •1.1.4 Groovy makes testing Java much easier
- •1.1.5 Groovy tools simplify your build
- •1.2 Groovy features that help Java
- •1.3 Java use cases and how Groovy helps
- •1.3.1 Spring framework support for Groovy
- •1.3.2 Simplified database access
- •1.3.3 Building and accessing web services
- •1.3.4 Web application enhancements
- •1.4 Summary
- •2 Groovy by example
- •2.1 Hello, Groovy
- •2.2 Accessing Google Chart Tools
- •2.2.1 Assembling the URL with query string
- •2.2.2 Transmitting the URL
- •2.2.3 Creating a UI with SwingBuilder
- •2.3 Groovy Baseball
- •2.3.1 Database data and Plain Old Groovy Objects
- •2.3.2 Parsing XML
- •2.3.3 HTML builders and groovlets
- •2.4 Summary
- •3 Code-level integration
- •3.1 Integrating Java with other languages
- •3.2 Executing Groovy scripts from Java
- •3.2.1 Using JSR223 scripting for the Java Platform API
- •3.2.2 Working with the Groovy Eval class
- •3.2.3 Working with the GroovyShell class
- •3.2.4 Calling Groovy from Java the easy way
- •3.2.5 Calling Java from Groovy
- •3.3 Summary
- •4 Using Groovy features in Java
- •4.1 Treating POJOs like POGOs
- •4.2 Implementing operator overloading in Java
- •4.3 Making Java library classes better: the Groovy JDK
- •4.4 Cool AST transformations
- •4.4.1 Delegating to contained objects
- •4.4.2 Creating immutable objects
- •4.4.3 Creating singletons
- •4.5 Working with XML
- •4.6 Working with JSON data
- •4.7 Summary
- •5 Build processes
- •5.1 The build challenge
- •5.2 The Java approach, part 1: Ant
- •5.3 Making Ant Groovy
- •5.3.1 The <groovy> Ant task
- •5.3.2 The <groovyc> Ant task
- •5.3.3 Writing your build in Groovy with AntBuilder
- •5.3.4 Custom build scripts with Gant
- •5.3.5 Ant summary
- •5.4 The Java approach, part 2: Maven
- •5.4.2 The GMaven project
- •5.4.3 Maven summary
- •5.5 Grapes and @Grab
- •5.6 The Gradle build system
- •5.6.1 Basic Gradle builds
- •5.6.2 Interesting configurations
- •5.7 Summary
- •6 Testing Groovy and Java projects
- •6.1 Working with JUnit
- •6.1.1 A Java test for the Groovy implementation
- •6.1.2 A Groovy test for the Java implementation
- •6.1.3 A GroovyTestCase test for a Java implementation
- •6.2 Testing scripts written in Groovy
- •6.2.1 Useful subclasses of GroovyTestCase: GroovyShellTestCase
- •6.2.2 Useful subclasses of GroovyTestCase: GroovyLogTestCase
- •6.3 Testing classes in isolation
- •6.3.1 Coerced closures
- •6.3.2 The Expando class
- •6.3.3 StubFor and MockFor
- •6.4 The future of testing: Spock
- •6.4.1 The Search for Spock
- •6.4.2 Test well, and prosper
- •6.4.4 The trouble with tribbles
- •6.4.5 Other Spock capabilities
- •6.5 Summary
- •7 The Spring framework
- •7.1 A Spring application
- •7.2 Refreshable beans
- •7.3 Spring AOP with Groovy beans
- •7.4 Inline scripted beans
- •7.5 Groovy with JavaConfig
- •7.6 Building beans with the Grails BeanBuilder
- •7.7 Summary
- •8 Database access
- •8.1 The Java approach, part 1: JDBC
- •8.2 The Groovy approach, part 1: groovy.sql.Sql
- •8.3 The Java approach, part 2: Hibernate and JPA
- •8.4 The Groovy approach, part 2: Groovy and GORM
- •8.4.1 Groovy simplifications
- •8.5 Groovy and NoSQL databases
- •8.5.1 Populating Groovy vampires
- •8.5.2 Querying and mapping MongoDB data
- •8.6 Summary
- •9 RESTful web services
- •9.1 The REST architecture
- •9.3 Implementing JAX-RS with Groovy
- •9.4 RESTful Clients
- •9.5 Hypermedia
- •9.5.1 A simple example: Rotten Tomatoes
- •9.5.2 Adding transitional links
- •9.5.3 Adding structural links
- •9.5.4 Using a JsonBuilder to control the output
- •9.6 Other Groovy approaches
- •9.6.1 Groovlets
- •9.6.2 Ratpack
- •9.6.3 Grails and REST
- •9.7 Summary
- •10 Building and testing web applications
- •10.1 Groovy servlets and ServletCategory
- •10.2 Easy server-side development with groovlets
- •10.2.1 A “Hello, World!” groovlet
- •10.2.2 Implicit variables in groovlets
- •10.3.2 Integration testing with Gradle
- •10.3.3 Automating Jetty in the Gradle build
- •10.4 Grails: the Groovy “killer app”
- •10.4.1 The quest for the holy Grails
- •10.5 Summary
- •A.1 Installing a JDK
- •A.2 Installing Groovy
- •A.3 Testing your installation
- •A.4 IDE support
- •A.5 Installing other projects in the Groovy ecosystem
- •B.1 Scripts and the traditional example
- •B.2 Variables, numbers, and strings
- •B.2.1 Numbers
- •B.2.2 Strings and Groovy strings
- •B.3 Plain Old Groovy Objects
- •B.4 Collections
- •B.4.1 Ranges
- •B.4.2 Lists
- •B.4.3 Maps
- •B.5 Closures
- •B.6 Loops and conditionals
- •B.6.1 Loops
- •B.6.2 Conditionals
- •B.6.3 Elvis
- •B.6.4 Safe de-reference
- •B.7 File I/O
- •B.8.1 Parsing and slurping XML
- •B.8.2 Generating XML
- •B.8.3 Validation
- •B.9 JSON support
- •B.9.1 Slurping JSON
- •B.9.2 Building JSON
- •index
- •Symbols
Making Ant Groovy |
97 |
Each task outputs its own name, followed by the included built-in Ant tasks indented underneath. The build completed successfully, though that can be misleading. The BUILD SUCCESSFUL statement at the end means that Ant finished all the tasks. The individual tasks may or may not have worked.
The tasks chosen here are typical, but there is no standard. Each organization (and even each developer) is free to choose their own. Reusing tasks between different builds also requires an import statement (or copy-and-paste reuse), plus some effort to make sure the tasks are not tied to a particular project structure.
Again, the benefit here is that this is all completely portable. The Ant build should work just as well on Mac OS X as it does on Windows or Linux. The downside is that this is a trivial Hello World application and the build file is already over 35 lines long. Once you add in the junit and junitreport tasks, to say nothing of customizing the classpath with third-party libraries, the size of this file will grow quickly. A more extensive build file, including the JUnit 4 libraries and a test case, can be found in the chapter source code.
Rather than do that here, however, let me show you how to introduce Groovy into this system.
5.3Making Ant Groovy
Ant is not as common in Java builds as it used to be, but switching build tools is a major decision for most organizations and not to be undertaken lightly. If you’re working with a large installed base of Ant builds, then Groovy can still contribute.
Four approaches are available:
■Groovy scripting code can be added directly to an Ant build file.
■Groovy scripts and classes can be compiled and executed in Ant builds using special Ant tasks for that purpose.
■The Groovy standard library contains a special class called groovy.util.AntBuilder that can replace the XML build file with Groovy scripting code that does the same thing.
■There’s a Groovy DSL available, called Gant, which provides an alternative to
AntBuilder.
ANTBUILDER Even if you don’t use Ant, the AntBuilder class is worth knowing about because it’s embedded in other build tools, like Gant and Gradle.
The following subsections will tackle each of these Groovy and Ant topics in turn.
5.3.1The <groovy> Ant task
Ant has two hooks that allow you to add Groovy to a standard build file. The <groovy> and <groovyc> tasks use the Groovy libraries to execute Groovy scripts and compile Groovy source files, respectively.
www.it-ebooks.info

98 |
CHAPTER 5 Build processes |
Starting first with <groovy>, defining the associated task in an Ant build lets you write Groovy code directly into the build file. The following listing shows a trivial example.
Listing 5.3 A trivial Ant build that executes Groovy code in a task
<?xml version="1.0" encoding="UTF-8"?> |
|
|
|
|
Access environment |
||
<project name="Groovy Ant" basedir="." default="info"> |
|||||||
<property environment="env" /> |
|
|
|
|
variables |
||
|
|
|
|
|
|||
<path id="groovy.classpath"> |
|
|
|
|
Use the groovy-all |
||
<fileset dir="${env.GROOVY_HOME}/embeddable" /> |
|
|
|
||||
|
|
JAR file |
|||||
</path> |
|
|
|
|
|||
|
|
|
|
|
|||
<taskdef name="groovy" |
|
|
|
|
Define the |
||
classname="org.codehaus.groovy.ant.Groovy" |
|||||||
groovy task |
|||||||
classpathref="groovy.classpath" /> |
|
|
|
|
|
||
<target name="info"> |
|
|
|
|
|
||
<groovy> |
|
Use the |
|
||||
println 'Hello, World!' |
|
||||||
groovy task |
|
ant.echo 'Hello, World!' </groovy>
</target>
</project>
The environment property allows the build to access system properties in the operating system. Here the env variable is used to access the current value of GROOVY_HOME, the installation directory for Groovy. The <path> element assigns the groovy-all JAR file (found in the embeddable directory) to the groovy.classpath ID.
The <taskdef> element then defines the groovy task as a reference to the org.codehaus.groovy.ant.Groovy class, which is resolved in the groovy-all JAR file. Once the groovy task has been defined it can be used to execute arbitrary Groovy code. A straight print of “Hello, World!” is executed, and then the Ant echo task is also called.
It’s therefore easy enough to add Groovy code to an existing Ant build file, which can be useful if looping or conditional logic is needed in the build. It’s notoriously difficult to “program” in XML, and technologies that tend that direction (like Ant and XSLT) often result in awkward, complex build files. Adding Groovy scripting code might help the build file without modifying the underlying source code.
5.3.2The <groovyc> Ant task
Say you follow the advice in this book and decide to add Groovy modules to your implementation code. If you’re still going to build with Ant you’ll need a compilation task, similar to <javac>, for Groovy. That task is <groovyc>.
The basic <groovyc> task definition is simple enough:
<taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" classpathref="groovy.classpath"/>
www.it-ebooks.info

Making Ant Groovy |
99 |
The name of the task is <groovyc>, and it’s backed by the Groovyc class in the org.codehaus.groovy.ant package. This class is part of the Groovy Ant JARs referenced in the earlier build file.
The result of this task definition is that you can compile Groovy classes with <groovyc> while you compile Java classes with <javac>. This enforced separation of code bases can lead to difficulties, however, if there are cross dependencies. For example, a Groovy class may implement a Java interface and reference a Java class, which in turn uses a Groovy class, and so on.
A good way to resolve these issues is to use the joint-compilation approach. Ant lets you embed the <javac> task inside the <groovyc> task. The nested tag approach results in a <groovyc> task that looks like this:
<groovyc srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath">
<javac source="1.5" target="1.5" /> </groovyc>
The nested <javac> task doesn’t imply the Java compiler is running. As a child of the <groovyc> task it lets the Groovy joint compiler do all the work.
The source directory, destination directory, and classpath variables defined in the <groovyc> task are passed down to the nested <javac> task. The joint-compilation approach means that Groovy will compile the Groovy sources and create stubs for them, then call the Java compiler to do the same for the Java sources, and resume the compilation process with the Groovy compiler. The result is that you can mix Java and Groovy sources without a problem.
Therefore, to extend the Ant build file presented section 5.2 to include Groovy files, make the additions and changes shown in the next listing.
Listing 5.4 Extending the “Hello, World” build to mix Java and Groovy sources
<path id="groovy.classpath">
<fileset dir="${env.GROOVY_HOME}/embeddable" /> </path>
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar" /> </path>
<taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" classpathref="groovy.classpath" />
...
<target name="compile">
<mkdir dir="${classes.dir}" />
<groovyc srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath">
<javac source="1.5" target="1.5" /> </groovyc>
</target>
www.it-ebooks.info

100 |
CHAPTER 5 Build processes |
The rest is the same as before.
If you’re committed to Ant builds using XML, that’s all there is to it. If, however, you’re willing to switch your build language to Groovy, there are a couple of other alternatives. The next two subsections use Groovy for the build language but are still fundamentally based on Ant.
5.3.3Writing your build in Groovy with AntBuilder
The standard Groovy library includes a class called groovy.util.AntBuilder. To use it you need to add the Java-based Ant JAR library files to your classpath, but once you do, AntBuilder lets you replace the XML syntax with Groovy.
Any task defined by Ant can be used through the AntBuilder class. For example, the following listing shows a simple script that makes a copy of its own source, verifies that it worked, and then deletes the copy.
Listing 5.5 antbuilder.groovy, which copies itself
def ant = new AntBuilder() String dir = 'src/main/groovy'
assert !(new File("$dir/antbuildercopy.groovy").exists())
ant.echo 'about to copy the source code' ant.copy file:"$dir/antbuilder.groovy",
tofile:"$dir/antbuildercopy.groovy"
assert (new File("$dir/antbuildercopy.groovy").exists())
ant.echo 'deleting the copied file' ant.delete file:"$dir/antbuildercopy.groovy"
Builder code and regular Groovy code are freely intermixed in this example. The Ant tasks used here are echo, copy, and delete, but it would be easy enough to use others like javac, junitreport, or even optional Ant tasks like mail. As long as the required Ant libraries are in the classpath, each will work.
There’s actually a simplification available. The with syntax is available as a part of Groovy’s metaprogramming capabilities. It can simplify the previous listing down to that shown in the next listing.
Listing 5.6 Simplifying the build script using the with method
ant.with |
{ |
echo |
'about to copy the source code' |
copy |
file:"$dir/antbuilder.groovy", |
|
tofile:"$dir/antbuildercopy.groovy" |
echo |
'deleting the copied file' |
delete file:"$dir/antbuildercopy.groovy"
}
The with method invokes the contained methods on the Ant builder.
www.it-ebooks.info

Making Ant Groovy |
101 |
AntBuilder can be used to script entire build files. It’s useful for creating a build file quickly, especially if you already know the corresponding Ant tasks well. Because AntBuilder is part of the standard Groovy library it can be used wherever you need to do build-related tasks. Even better, Gradle build files include an instance of AntBuilder, making the migration path from Ant to Gradle much simpler.
A more interesting example is given in the next listing, which is a port of the original Ant build shown in listing 5.1.
Listing 5.7 A Groovy AntBuilder script port of the build.xml file from listing 5.1
AntBuilder ant = new AntBuilder()
String srcDir = 'src' String buildDir = 'build'
String classesDir = "${buildDir}/classes" String jarDir = "${buildDir}/jar"
String reportDir = "${buildDir}/reports" String libDir = 'lib'
Instantiate the builder
Port of <property> elements
ant.with { path(id:'classpath') {
fileset dir:libDir, includes:"**/*.jar"
}
Use builder as delegate for unrecognized methods in block
path id:'application', location:"$jarDir/HelloAntBuilder.jar"
delete dir:buildDir
mkdir dir:classesDir
Compile Java
javac(srcdir:srcDir, destDir:classesDir, includeantruntime:false, classpathref:'classpath')
mkdir dir:jarDir |
|
|
|
|
jar(destfile:"${jarDir}/HelloAntBuilder.jar", basedir:classesDir) { |
Build |
|||
manifest { |
|
|
|
|
attribute name:'Main-Class', value:'mjg.HelloWorld' |
JAR |
|||
} |
|
|
|
|
} |
|
|
|
|
mkdir dir:reportDir |
|
|
|
|
|
|
|
|
|
junit(printsummary:'yes') { |
|
|
|
|
classpath { |
|
|
|
|
path refid:'classpath' |
|
|
|
|
path refid:'application' |
|
|
|
|
} |
|
|
Run tests |
|
formatter type:'xml' |
|
|
|
|
batchtest(fork:'yes', todir:reportDir) { |
|
|
|
|
fileset dir:srcDir, includes:"**/*Test.java" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
junitreport(todir:reportDir) { |
|
Generate |
|
|
|
|
|||
fileset dir:reportDir, includes:"TEST-*.xml" |
|
|
||
report todir:reportDir |
|
test report |
|
|
} |
|
|
|
|
www.it-ebooks.info