
- •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
114 |
CHAPTER 5 Build processes |
5.5Grapes and @Grab
The Grape mechanism allows you to declare library dependencies directly inside a Groovy script. This is useful when you need to deliver a script to a client that doesn’t already have the required dependencies but is willing to download them as part of the build process.
The overall API is called Grape (Groovy Adaptable/Advanced Packaging Engine) and starts with the groovy.lang.Grab annotation. It uses an Ivy resolver to identify and download dependencies. Its primary use case is on scripts, so that they can be delivered to a client without any setup requirements other than having Groovy installed. At runtime Groovy will download and install any declared libraries and their transitive dependencies as part of the execution process.
GRAPE USE CASE Grape allows you to deliver a simple script that can be executed by a client without any setup necessary other than installing Groovy, making it particularly convenient for testers or QA people.
To demonstrate the Grape system, let me choose the Math library from the Apache Commons project (http://commons.apache.org/math/). Specifically, I want to work with the complex numbers package. The package includes a class called Complex, which represents complex numbers. Although the class is interesting in itself, it also makes for a nice demonstration of Groovy’s metaprogramming capabilities.
In Maven syntax the library has a group ID of org.apache.commons, an artifact ID of commons-math3, and a version of 3.0. Therefore, the format of the @Grab annotation is as shown in the following script:
import org.apache.commons.math3.complex.*
@Grab('org.apache.commons:commons-math3:3.0') Complex first = new Complex(1.0, 3.0); Complex second = new Complex(2.0, 5.0);
The @Grab annotation downloads both the given library and its dependencies. The syntax uses Maven structure, using colons to connect the group ID, the artifact ID, and the version number. Alternatively, you can specify the sections individually:
@Grab(group='org.apache.commons', module='commons-math3', version='3.0')
The behavior is equivalent in either case.
There isn’t much more to Grapes than this. In order to show an interesting example that requires an external Java library, let me present a simple case of Groovy metaprogramming. There’s nothing about it that requires Grapes in particular, but it shows how a small amount of metaprogramming can make a Java library class groovier. Using Grapes in the script allows me to send it to a client without compiling it or providing the library dependencies. The Grape annotations will handle the rest.
www.it-ebooks.info
Grapes and @Grab |
115 |
The Complex class represents a complex number, which combines real and imaginary parts. The class contains a two-argument constructor, as shown, that takes the real and imaginary parts as parameters. Many methods are defined on the class, so that it generalizes basic numerical computations to the complex domain.
Recall that in Groovy every operator delegates to a method call. Interestingly enough, the Complex class already has a method called multiply for computing the product of two complex numbers. Because the * operator in Groovy uses the multiply method, that operator can be used immediately:
assert first.multiply(second) == first * second
Again, this is a Java class. Fortunately, the developers of the class chose to include a method called multiply, so Groovy can use the * operator with complex numbers.
What about all the other mathematical operations? Most don’t line up as cleanly. For example, the class uses add instead of plus and subtract instead of minus. It’s easy to connect them, however, by adding the appropriate methods to the metaclass associated with Complex when viewed through Groovy.
As a reminder, every class accessed through Groovy contains a metaclass, and the metaclass is an Expando. This means that methods and properties can be added to the metaclass as desired, and the resulting members will be part of any instantiated object. Here’s how to add several mathematical operations to Complex:
Complex.metaClass.plus = { Complex c -> delegate.add c } Complex.metaClass.minus = { Complex c -> delegate.subtract c } Complex.metaClass.div = { Complex c -> delegate.divide c } Complex.metaClass.power = { Complex c -> delegate.pow c } Complex.metaClass.negative = { delegate.negate() }
That takes care of the +, -, /, **, and negation operators, respectively. In each case, the relevant method is defined on the metaclass by setting it equal to a closure. The associated closure takes a Complex argument (in the case of binary operators) and invokes the desired existing method on the closure’s delegate, passing along the argument.
CLOSURE DELEGATES Every closure has a delegate property. By default the delegate points to the object that the closure was invoked on.
After adding those methods to the metaclass, the operators can be used in the Groovy script:
assert new Complex(3.0, 8.0) == first + second assert new Complex(1.0, 2.0) == second - first
assert new Complex(0.5862068965517241, 0.03448275862068969) == first / second
assert new Complex(-0.007563724861696302, 0.01786136835085382) == first ** second
assert new Complex(-1.0, -3.0) == -first
www.it-ebooks.info

116 |
CHAPTER 5 Build processes |
To complete this part of the story I want to demonstrate the famous equation known as Euler’s identity,9 which is expressed as
e iπ = –1
This equation connects the imaginary numbers (i) and the transcendental numbers (e and π) to the negative numbers (–1). Euler found this expression so profound he had it inscribed on his tombstone.
The java.lang.Math class contains constants Math.E and Math.PI, and the Complex class has the constant Complex.I. To make the formula look better I’ll use static imports for all of them.
One final addition is necessary to make this work. Math.E in Java is of type double, and I want to raise it to a Complex power. The easiest way to do that is to convert the double to an instance of the Complex class and then use the pow method in the Complex class. Returning to Groovy metaprogramming, I need a power method (which corresponds to the ** operator) on Double that takes a Complex argument:
Double.metaClass.power = { Complex c -> (new Complex(delegate,0)).pow(c) }
With all that machinery in place the resulting code is a bit anticlimactic, but that’s a good thing:
Complex result = E ** (I * PI) assert result.real == -1
assert result.imaginary < 1.0e-15
As usual in Groovy, accessing the real or imaginary property is equivalent to calling the getReal or getImaginary method, respectively. The expression does generate a real part of –1, but the imaginary part isn’t exactly zero due to the round-off error associated with Java doubles. On my machine it evaluates to a number less than the bound shown, which is certainly close enough.
There are a few additional annotations available in the Grapes system. One is @GrabConfig, used in the next example when loading a database driver. The following script uses the groovy.sql.Sql class to generate an H2 database and add some data to it:
import groovy.sql.Sql
@GrabConfig(systemClassLoader=true) @Grab(group='com.h2database', module='h2', version='1.2.140')
Sql sql = Sql.newInstance(url:'jdbc:h2:mem:',driver:'org.h2.Driver')
The annotations provide the driver, so the Sql class can be used normally.
Because a member of a class can only have a single instance of a particular annotation, the @Grapes annotation is used to combine multiple @Grab annotations. The next listing computes complex values and stores them in a database table.
9Leonhard Euler (1707 – 1783) was one of the most brilliant mathematicians of all time. His work spanned virtually every field of math and science, and his collected works filled between 60 and 80 quarto volumes. The transcendental number e is named after him.
www.it-ebooks.info