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

The Groovy approach, part 1: groovy.sql.Sql |
203 |
ResultSet rs = pst.executeQuery(); if (rs.next()) {
p = new Product(); p.setId(rs.getInt("id")); p.setName(rs.getString("name")); p.setPrice(rs.getDouble("price"));
}
rs.close();
}catch (SQLException e) { e.printStackTrace();
}finally {
try {
if (pst != null) pst.close(); if (conn != null) conn.close();
} catch (SQLException e) { e.printStackTrace();
}
}
return p;
The essence; everything else is ceremony
}
As with so many things in Java, the best thing you can say about this code is that eventually you get used to it. All that’s being done here is to execute a select statement with a where clause including the necessary product ID and converting the returned database row into a Product object. Everything else is ceremony.
I could go on to show the remaining implementation methods, but suffice it to say that the details are equally buried. See the book source code for details.
Lessons learned (JDBC)
1JDBC is a very verbose, low-level set of classes for SQL access to relational databases.
2The Spring JdbcTemplate class (covered in chapter 7) is a good choice if Groovy is not available.
Years ago this was the only realistic option for Java. Now other options exist, like Spring’s JdbcTemplate (discussed in chapter 7 on Spring) and object-relational mapping tools like Hibernate (discussed later in this chapter). Still, if you already know SQL and you want to implement a DAO interface, Groovy provides a very easy alternative: the groovy.sql.Sql class.
8.2The Groovy approach, part 1: groovy.sql.Sql
The groovy.sql.Sql class is a simple façade over JDBC. The class takes care of resource management for you, as well as creating and configuring statements and logging errors. It’s so much easier to use than regular JDBC that there’s never any reason to go back.
The next listing shows the part of the class that sets up the connection to the database and initializes it.
www.it-ebooks.info

204 |
CHAPTER 8 Database access |
Listing 8.6 A ProductDAO implementation using the groovy.sql.Sql class
import groovy.sql.Sql
class SqlProductDAO implements ProductDAO {
Sql sql = Sql.newInstance(url:'jdbc:h2:mem:', driver:'org.h2.Driver')
SqlProductDAO() { sql.execute '''
create table product ( id int primary key, name varchar(25), price double
)''' sql.execute """
insert into product values (1,'baseball',4.99), (2,'football',14.95), (3,'basketball',14.99)"""
}
// ... more to come ...
}
Configure the database properties
Multiline strings to make reading easier
The groovy.sql.Sql class contains a static factory method called newInstance that returns a new instance of the class. The method is overloaded for a variety of parameters; see the GroovyDocs for details.
The execute method takes an SQL string and, naturally enough, executes it. Here I’m using a multiline string to make the create table and insert into statements easier to read. The Sql class takes care of opening a connection and closing it when finished.
THE SQL CLASS The groovy.sql.Sql class does everything raw JDBC does, and handles resource management as well.
The same execute method can be used to delete products:
void deleteProduct(int id) {
sql.execute 'delete from product where id=?', id
}
The execute method not only creates the prepared statement, it also inserts the provided ID into it and executes it. It’s hard to get much simpler than that.
Inserting products can use the same method, but with a list of parameters:
void insertProduct(Product p) {
def params = [p.id, p.name, p.price] sql.execute
'insert into product(id,name,price) values(?,?,?)', params
}
The class has another method called executeInsert, which is used if any of the columns are auto-generated by the database. That method returns a list containing the
www.it-ebooks.info

The Groovy approach, part 1: groovy.sql.Sql |
205 |
generated values. In this example the id values are supplied in the program. Autogenerated values will be considered in section 8.3 on Hibernate and JPA.
Retrieving products involves a minor complication. There are several useful methods for querying. Among them are firstRow, eachRow, and rows. The firstRow method is used when a single row is required. Either eachRow or rows can be used if there are multiple rows in the result set. In that case, eachRow returns a map of column names to column values, and the rows method returns a list of maps, one for each row.
The complication is that the returned column names are in all capitals. For example, the query
sql.firstRow 'select * from product where id=?', id
returns
[ID:1, NAME:baseball, PRICE:4.99]
for an id of 1. Normally I’d like to use that map as the argument to the Product constructor, but because the Product attributes are all lowercase that won’t work.
One possible solution is to transform the map into a new one with lowercase keys. That’s what the collectEntries method in the Map class is for. The resulting implementation of the findProductById method is therefore
Product findProductById(int id) {
def row = sql.firstRow('select * from product where id=?', id)
new Product( row.collectEntries { k,v -> [k.toLowerCase(), v] } );
}
It would be easy enough to generalize this to the getAllProducts method by using eachRow and transforming them one at a time. A somewhat more elegant solution is to use the rows method and transform the resulting list of maps directly:
List<Product> getAllProducts() {
sql.rows('select * from product').collect { row -> new Product(
row.collectEntries { k,v -> [k.toLowerCase(), v] }
)
}
}
This solution is either incredibly elegant or too clever by half, depending on your point of view. Collecting2 everything together (except for the initialization shown in the constructor already), the result is shown in the following listing.
2 No pun intended.
www.it-ebooks.info

206 CHAPTER 8 Database access
Listing 8.7 The complete SqlProductDAO class, except for the parts already shown
class SqlProductDAO implements ProductDAO {
Sql sql = Sql.newInstance(url:'jdbc:h2:mem:',driver:'org.h2.Driver')
List<Product> getAllProducts() {
sql.rows('select * from product').collect { row -> new Product(
row.collectEntries { k,v -> [k.toLowerCase(), v] }
)
}
}
Product findProductById(int id) {
def row = sql.firstRow('select * from product where id=?', id) new Product(
row.collectEntries { k,v -> [k.toLowerCase(), v] } );
}
void insertProduct(Product p) {
def params = [p.id, p.name, p.price] sql.execute
'insert into product(id,name,price) values(?,?,?)', params
}
void deleteProduct(int id) {
sql.execute 'delete from product where id=?', id
}
}
By the way, there’s one other option available,3 but only if the Person class is implemented in Groovy. If so, I can add a constructor to the Person class that handles the case conversion there:
class Product { int id String name double price
Person(Map args) { args.each { k,v ->
setProperty( k.toLowerCase(), v)
}
}
}
With this constructor, the getAllProducts method reduces to
List<Product> getAllProducts() {
sql.rows('select * from product').collect { new Product(it) }
}
It’s hard to beat that for elegance.
3 Thanks to Dinko Srkoc on the Groovy Users email list for this helpful suggestion.
www.it-ebooks.info

The Groovy approach, part 1: groovy.sql.Sql |
207 |
Going meta
The “elegant” solution in the chapter breaks down if the class attributes use camel case, which is normal. The corresponding database table entries would then use underscores to separate the words.
As shown by Tim Yates on the Groovy Users email list,4 you can use Groovy metaprogramming to add a toCamelCase method to the String class to do the conversion. The relevant code is
String.metaClass.toCamelCase = {-> delegate.toLowerCase().split('_')*.capitalize().join('').with {
take( 1 ).toLowerCase() + drop( 1 )
}
}
Every Groovy class has a metaclass retrieved by the getMetaClass method. New methods can be added to the metaclass by assigning closures to them, as is done here. A no-arg closure is used, which implies that the new method will take zero arguments.
Inside the closure the delegate property refers to the object on which it was invoked. In this case it’s the string being converted. The database table columns are in uppercase separated by underscores, so the delegate is converted to lowercase and then split at the underscores, resulting in a list of strings.
Then the spread-dot operator is used on the list to invoke the capitalize method on each one, which capitalizes only the first letter. The join method then reassembles the string.
Then comes the fun part. The with method takes a closure, and inside that closure any method without a reference is invoked on the delegate. The take and drop methods are used on lists (or, in this case, a character sequence). The take method retrieves the number of elements specified by its argument. Here that value is 1, so it returns the first letter, which is made lowercase. The drop method returns the rest of the elements after the number in the argument is removed, which in this case means the rest of the string.
The result is that you can call the method on a string and convert it. 'FIRST_NAME'
.toLowerCase() becomes 'firstName', and so on.
Welcome to the wonderful world of Groovy metaprogramming.
The advantages of groovy.sql.Sql over raw JDBC are obvious. If I have SQL code already written, I always use it. 4
4 See http://groovy.329449.n5.nabble.com/Change-uppercase-Sql-column-names-to-lowercase-td5712088.html for the complete discussion.
www.it-ebooks.info