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

320 |
APPENDIX B Groovy by feature |
assert books.book.find { it.@isbn == "9781935182948"
}.title == "Making Java Groovy"
def prices = [] books.book.price.each {
prices << it.toDouble()
}
assert prices == [39.99, 35.99, 35.99, 27.50] assert prices.sum() == 139.47
Groovy uses two different classes for working with XML. The previous example used an XmlSlurper. Groovy also includes an XmlParser. The XmlParser creates a tree of Node instances, so if you need to approach the file from a node point of view, use the parser. The result is that you’ll need to invoke a text method on each node to retrieve the text data, but otherwise the two approaches are virtually the same.
Parsing XML is therefore quite easy. What about generating XML? That’s the subject of the next subsection.
B.8.2 Generating XML
So far, most of the Groovy capabilities presented are similar to what Java can do, just simpler or easier. In this section I’ll show a Groovy builder, which uses Groovy’s metaprogramming to go beyond what Java can do.
To generate XML, Groovy provides a class called groovy.xml.MarkupBuilder. You use a MarkupBuilder by invoking methods that don’t exist, and the builder interprets them by generating XML elements and attributes.
That sounds strange, but is simple in practice. The next listing shows an example.
Listing B.6 Generating XML using a MarkupBuilder
def builder = new groovy.xml.MarkupBuilder() def department = builder.department {
deptName "Construction" employee(id:1) {
empName "Fred"
}
employee(id:2) { empName "Barney"
}
}
After instantiating the MarkupBuidler I invoke the department method on it, omitting the optional parentheses. There’s no department method on MarkupBuilder, so what does Groovy do?
If this was Java, I would fail with something like a MissingMethodException. Every class in Groovy has an associated meta class, however, and the meta class has a method called methodMissing. The meta class is the key to Groovy’s code generation capabilities. When the methodMissing method in MarkupBuilder is called, the
www.it-ebooks.info
XML |
321 |
implementation ultimately is to generate an XML element with the method name as the element name.
The braces that follow are interpreted to mean a child element is next. The name of the child element will be deptName, and its character data will be the supplied string. The next element is an employee, and the map-like syntax for the id implies an attribute on the employee element is needed, and so on.
The result of executing this script is
<department>
<deptName>Construction</deptName> <employee id='1'>
<empName>Fred</empName>
</employee> <employee id='2'>
<empName>Barney</empName>
</employee>
</department>
The MarkupBuilder generates the XML. It’s hard to imagine a simpler way to solve that problem.
I want to illustrate one final aspect of XML processing with Groovy, which involves validating a document.
B.8.3 Validation
XML documents are validated in one of two ways: through either a Document Type Definition (DTD) or an XML schema. The DTD system is older, simpler, and much less useful, but the Java parsers have been able to validate against them almost from the beginning. Schema validation came much later but is far more important, especially when dealing with, for example, web services.
Validating XML with Groovy is an interesting demonstration both of what Groovy provides, and what to do if Groovy doesn’t provide anything.
First, consider validation against a DTD. Here’s a DTD for the library XML shown earlier:
<!ELEMENT library (book+)>
<!ELEMENT book (title,author+,price)> <!ATTLIST book
isbn CDATA #REQUIRED> <!ELEMENT title (#PCDATA)> <!ELEMENT author (#PCDATA)> <!ELEMENT price (#PCDATA)>
The idea is that a library element contains one or more books. A book element contains a title, one or more author elements, and a price, in that order. The book element has an attribute called isbn, which is a simple string but is required. The title, author, and price elements all consist of simple strings.
To tie the XML file to the DTD, I add the following line before the root element:
<!DOCTYPE library SYSTEM "library.dtd">
www.it-ebooks.info

322 |
APPENDIX B Groovy by feature |
Validating the XML file against the DTD is then almost trivial. The XmlSlurper class has an overloaded constructor that takes two arguments, both of which are Booleans. The first is to trigger validation, and the second is namespace awareness. Namespaces aren’t relevant when discussing a DTD, but it doesn’t hurt to turn on both properties:
def root = new XmlSlurper(true, true).parse(fileName)
That’s all that’s needed to do the validation. If the XML data doesn’t satisfy the DTD, errors will be reported by the parsing process.
Validation against an XML schema has always been more of a challenge. Schemas understand namespaces and namespace prefixes, and there are many things you can do in a schema that you can’t do in a DTD.
Consider the next listing, which shows a schema for the library.
Listing B.7 An XML schema for the library XML
<?xml version="1.0" encoding="UTF-8"?> <schema
xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.kousenit.com/books" xmlns:tns="http://www.kousenit.com/books" elementFormDefault="qualified">
<element name="library" type="tns:LibraryType" /> <complexType name="LibraryType">
<sequence>
<element ref="tns:book" maxOccurs="unbounded" /> </sequence>
</complexType> <element name="book">
<complexType>
<sequence>
<element name="title" type="string" /> <element name="author" type="string"
maxOccurs="unbounded" />
<element name="price" type="tns:PriceType" /> </sequence>
<attribute name="isbn" type="tns:ISBNtype" /> </complexType>
</element>
<simpleType name="PriceType"> <restriction base="decimal">
<fractionDigits value="2" /> </restriction>
</simpleType>
<simpleType name="ISBNtype"> <restriction base="string">
<pattern value="\d{10}|\d{13}" /> </restriction>
</simpleType>
</schema>
www.it-ebooks.info