
- •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

220 |
CHAPTER 8 Database access |
8.5Groovy and NoSQL databases
One of the most interesting trends in software development in the past few years15 has been the growth of alternative, non-relational databases. The generic term NoSQL (which the majority of the community interpret as “Not Only SQL”) refers to a range of schema-less databases that are not based on relational approaches.
The subject of NoSQL databases is already large and rapidly growing, and it’s well beyond the scope of this book. But many of the databases have a Java API, and some of them also have Groovy wrappers that simplify them.
One of the most interesting is MongoDB,16 whose Java API is rather awkward but is dramatically improved through a Groovy wrapper called GMongo. The GMongo project, whose GitHub repository is located at https://github.com/poiati/gmongo, is the product of Paulo Poiati and is the subject of this section.
MongoDB is a document-oriented database that stores its data in binary JSON (BSON) format. This makes it perfect for storing data downloaded from RESTful web services, which often produce JSON data on request.
8.5.1Populating Groovy vampires
This example came about because I was wandering in a bookstore recently and noticed that while there was only one bookshelf labeled “Computer,” there were three others labeled “Teen Paranormal Romance.” Rather than lament the decline of Western Civilization I chose to take this as evidence that I needed to add Groovy vampires to my book.
Consider the web service provided by the movie review site Rotten Tomatoes, http://developer.rottentomatoes.com. If you register for an API key, you can make HTTP GET requests that search for movies, cast members, and more. The data is returned in JSON form. The base URL for the API is located at http://api.rottentomatoes
.com/api/public/v1.0. All requests start with that URL.
For example, searching for information about the movie Blazing Saddles17 is done by accessing http://api.rottentomatoes.com/api/public/v1.0/movies.json?q=Blazing %20Saddles&apiKey=... (supply the API key in the URL). The result is a JSON object that looks like the following listing.
Listing 8.15 A portion of the JSON object representing the movie Blazing Saddles
{
"total": 1, "movies": [
{
"id": "13581",
"title": "Blazing Saddles",
15Other than the rise of dynamic languages on the JVM, of course.
16See www.mongodb.org/ for downloads and documentation.
17That’s not a vampire movie, obviously, but the urge to save Mongo in MongoDB is irresistible. “Mongo only pawn in game of life” is a brilliant line and arguably the peak of the Alex Karras oeuvre.
www.it-ebooks.info
Groovy and NoSQL databases |
221 |
"year": 1974, "mpaa_rating": "R", "runtime": 93, "release_dates": {
"theater": "1974-02-07", "dvd": "1997-08-27"
}, "ratings": {
"critics_rating": "Certified Fresh", "critics_score": 89, "audience_rating": "Upright", "audience_score": 89
},
"synopsis": "",
..., "abridged_cast": [
{
"name": "Cleavon Little", "id": "162693977", "characters": [
"Bart"
]
},
{
"name": "Gene Wilder", "id": "162658425", "characters": [
"Jim the Waco Kid"
]
},
...
], "alternate_ids": {
"imdb": "0071230"
},
...
}
In addition to the data shown, the JSON object also has links to the complete cast list, reviews, and more. Another reason to use a database like MongoDB for this data is that not every field appears in each movie. For example, some movies contain a critic’s score and some do not. This fits with the whole idea of a schema-less database based on JSON.
First, to populate the MongoDB I’ll use an instance of the com.gmongo.GMongo class. This class wraps the Java API directly. In fact, if you look at the class in GMongo.groovy, you’ll see that it consists of
class GMongo {
@Delegate Mongo mongo
// ... Constructors and other methods ...
}
www.it-ebooks.info

222 |
CHAPTER 8 Database access |
There follow various constructors and simple patch methods. The @Delegate annotation from Groovy is an Abstract Syntax Tree (AST) transformation18 that exposes the methods in the com.mongodb.Mongo class, which comes from the Java API, through GMongo. The AST transformation means you don’t need to write all the delegate methods by hand.
Initializing a database is as simple as
GMongo mongo = new GMongo() def db = mongo.getDB('movies') db.vampireMovies.drop()
MongoDB uses movies as the name of the database, and collections inside it, like vampireMovies, are properties of the database. The drop method clears the collection.
Searching Rotten Tomatoes consists of building a GET request with the proper parameters. In this case, the following code searches for vampire movies:
String key = new File('mjg/rotten_tomatoes_apiKey.txt').text
String base = "http://api.rottentomatoes.com/api/public/v1.0/movies.json?" String qs = [apiKey:key, q:'vampire'].collect { it }.join('&')
String url = "$base$qs"
The API key is stored in an external file. Building the query string starts with a map of parameters, which is transformed into a map of strings of the form “key=value” and then joined with an ampersand. The full URL is then the base URL with an appended query string. Getting the movies and saving them into the database is almost trivial:
def vampMovies = new JsonSlurper().parseText(url.toURL().text) db.vampireMovies << vampMovies.movies
The JsonSlurper receives text data in JSON form from the URL and converts it to JSON objects. Saving the results into the database is as simple as appending the whole collection.
The API has a limit of 30 results per page. The search results include a property called next that points to the next available page, assuming there is one. The script therefore needs to loop that many times to retrieve the available data:
def next = vampMovies?.links?.next while (next) {
println next
vampMovies = slurper.parseText("$next&apiKey=$key".toURL().text) db.vampireMovies << vampMovies.movies
next = vampMovies?.links?.next
}
That’s all there is to it. Using a relational database would require mapping the movie structure to relational tables, which would be a bit of a challenge. Because MongoDB uses BSON as its native format, even a collection of JSON objects can be added with no work at all.
18Discussed in chapter 4 on integration and in appendix B, “Groovy by Feature,” and used in many other places in this book.
www.it-ebooks.info

Groovy and NoSQL databases |
223 |
Figure 8.5 A portion of the vampire movies database, using the MonjaDB plugin for Eclipse
There’s an Eclipse plugin, called MonjaDB, which connects to MongoDB databases. Figure 8.5 shows a portion of the vampireMovies database.
8.5.2Querying and mapping MongoDB data
Now that the data is in the database I need to be able to search it and examine the results. This can be done in a trivial fashion, using the find method, or the data can be mapped to Groovy objects for later processing.
The find method on the collection returns all JSON objects satisfying a particular condition. If all I want is to see how many elements are in the collection, the following suffices:
println db.vampireMovies.find().count()
With no arguments, the find method returns the entire collection. The count method then returns the total number.
Mapping JSON to Groovy brings home the difference between a strongly typed language, like Groovy, and a weakly typed language, like JSON. The JSON data shown is a mix of strings, dates, integers, and enumerated values, but the JSON object has no embedded type information. Mapping this to a set of Groovy objects takes some work.
For example, the following listing shows a Movie class that holds the data in the JSON object.
Listing 8.16 Movie.groovy, which wraps the JSON data
@ToString(includeNames=true) class Movie {
long id String title int year
MPAARating mpaaRating int runtime
String criticsConsensus
www.it-ebooks.info

224 |
CHAPTER 8 Database access |
Map releaseDates = [:] Map<String, Rating> ratings = [:] String synopsis
Map posters = [:]
List<CastMember> abridgedCast = [] Map links = [:]
}
The Movie class has attributes for each contained element, with the data types specified. It contains maps for the release dates, posters, ratings, and additional links, and a list for the abridged cast. A CastMember is just a POGO:
class CastMember { String name long id
List<String> characters = []
}
A Rating holds a string and an integer:
class Rating { String rating int score
}
Just to keep things interesting, the MPAA rating is a Java enum, though it could just as easily have been implemented in Groovy:
public enum MPAARating {
G, PG, PG_13, R, X, NC_17, Unrated
}
Converting a JSON movie to a Movie instance is done through a static method in the Movie class. A portion of the fromJSON method is shown in the next listing.
Listing 8.17 A portion of the method that converts JSON movies to Movie instances
static Movie fromJSON(data) { Movie m = new Movie() m.id = data.id.toLong() m.title = data.title
m.year = data.year.toInteger() switch (data.mpaa_rating) {
case 'PG-13' : m.mpaaRating = MPAARating.PG_13; break case 'NC-17' : m.mpaaRating = MPAARating.NC_17; break default :
m.mpaaRating = MPAARating.valueOf(data.mpaa_rating)
}
m.runtime = data.runtime
m.criticsConsensus = data.critics_consensus ?: ''
The complete listing can be found in the book source code but isn’t fundamentally different from what’s being shown here.
www.it-ebooks.info

Groovy and NoSQL databases |
225 |
A test to prove the conversion is working is shown in the following listing.
Listing 8.18 A JUnit test to verify the JSON conversion
class MovieTest { @Test
void testFromJSON() {
def data = new JsonSlurper().parseText(
new File('src/main/groovy/mjg/blazing_saddles.txt').text) Movie.fromJSON(data.movies[0]).with {
assert id == 13581
assert title == 'Blazing Saddles' assert year == 1974
assert mpaaRating == MPAARating.R assert runtime == 93
assert releaseDates ==
['theater':'1974-02-07', 'dvd':'1997-08-27'] assert ratings['critics'].rating == 'Certified Fresh' assert ratings['critics'].score == 89
assert ratings['audience'].rating == 'Upright' assert ratings['audience'].score == 89
assert synopsis == '' assert posters.size() == 4
assert abridgedCast.size() == 5
assert abridgedCast[0].name == 'Cleavon Little' assert abridgedCast[0].id == 162693977
assert abridgedCast[0].characters == ['Bart'] assert links.size() == 6
}
}
}
Use Movie methods in the closure
Lessons learned (NoSQL19)
1NoSQL databases like MongoDB, Neo4J, and Redis are becoming quite common for specific use cases.
2Most NoSQL databases make a Java-based API available, which can be called directly from Groovy.
3Often a Groovy library will be available that wraps the Java API and simplifies it. Here, GMongo is used as an example.
Once the mapping works, finding all vampire movies that have a critic’s consensus is as simple as the following script:19
GMongo mongo = new GMongo() def db = mongo.getDB('movies')
db.vampireMovies.find([critics_consensus : ~/.*/]).each { movie -> println Movie.fromJSON(movie)
}
19 NoSQL version of Worst SQL Joke Ever Told: DBA walks into a NoSQL bar; can’t find a table, so he leaves.
www.it-ebooks.info