- •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 Spring framework
This chapter covers
■Using Groovy classes in Spring applications
■Refreshable beans
■Inline scripted beans
■The Grails BeanBuilder class
■Spring AOP with Groovy classes
As Java frameworks go, Spring is one of the most successful. Spring brought the ideas of dependency injection, complex object lifecycle management, and declarative services for POJOs to the forefront of Java development. It’s a rare project that doesn’t at least consider taking advantage of all Spring has to offer, including the vast array of Spring “beans” included in its library. Spring touches almost every facet of enterprise Java development, in most cases simplifying them dramatically.
In this chapter I’ll look at how Groovy interacts with the Spring framework. As it turns out, Groovy and Spring are old friends. Spring manages Groovy beans as easily as it handles Java. Spring includes special capabilities for working with code from dynamic languages, however, which I’ll review here.
167
www.it-ebooks.info
168 |
CHAPTER 7 The Spring framework |
|
POJO |
POGO |
|
|
Java |
AOP |
Closure |
Groovy |
|
coercion |
||||
|
|
|
||
|
Refreshable |
Inline scripted |
|
|
|
beans |
beans |
|
|
|
BeanBuilder |
Spock |
|
|
|
Spring |
|
||
|
|
|
Spring + Groovy
Figure 7.1 Guide to the Spring technologies with Groovy. Spring manages POGOs as easily as POJOs, so the examples include Groovy implementations of both normal beans and aspects. Closure coercion is used to implement the RowMapper interface in a JdbcTemplate. Refreshable beans are Groovy source files that can be modified at runtime. Inline scripted beans are included inside XML configuration files. Grails provides a BeanBuilder class for configuring beans. Finally, Spock has a library that allows it to be used with Spring’s test context feature.
Groovy can be used to implement beans or to configure them. In this chapter I’ll try to review all the ways Groovy can help Spring. Figure 7.1 contains a guide to the technologies discussed in this chapter.
To show how Groovy helps Spring, I need to review what Spring is all about and how it’s used and configured. I’ll start with a simple, but non-trivial, sample application. Rather than show all the pieces (which are in the source code repository for the book), I’ll highlight the overall architecture and the Groovy parts.
7.1A Spring application
For all its benefits, Spring is a hard framework to demonstrate to developers unfamiliar with it. The “Hello, World” application in Spring makes you question why you’d ever want it, because it replaces a couple of lines of simple, easy-to-understand, strongly typed Java with several additional lines of code, plus about 20 lines of XML. That’s not exactly a ringing endorsement.
To see the real value of Spring you have to see a real application, even if it’s simplified in various ways. The following application models the service and persistence layers of an account management application. The presentation layer is arbitrary, so the following code could be used in either a client-side or a server-side application. In this case, I’ll demonstrate the functionality through both unit and integration tests.
www.it-ebooks.info
A Spring application |
169 |
JAVA AND GROOVY SPRING BEANS Rather than build the entire application in Java and then convert it to Groovy as in other chapters, to save space this application mixes both languages. The point is that Spring managed beans can be implemented in either Java or Groovy, whichever is most convenient.
Consider an application that manages bank accounts. I’ll have a single entity class representing an account, with only an id and a balance, along with deposit and withdraw methods.
The next listing shows the Account class in Groovy, which has a serious advantage over its Java counterpart: it makes it easy to work with a java.math.BigDecimal.
Listing 7.1 An Account POGO in Groovy that uses BigDecimal
import groovy.transform.EqualsAndHashCode import groovy.transform.ToString
@EqualsAndHashCode(includes=['id'])
AST transformations
@ToString(includeNames=true) class Account {
Integer id BigDecimal balance
def deposit(amount) { balance += amount
} |
|
Using operators |
def withdraw(amount) { |
|
with BigDecimal |
|
|
|
balance -= amount |
|
|
|
|
|
} |
|
|
}
Financial calculations are one of the reasons we need java.math.BigDecimal and java.math.BigInteger. Using BigDecimal keeps round-off errors from being sent into an account where it can accumulate over time.1 It’s easy to show how quickly round-off errors can become a problem. Consider the following two lines:
println 2.0d – 1.1d println 2.0 – 1.1
The first line uses doubles, while the second line uses java.math.BigDecimal. The first evaluates to 0.8999999999999999, while the second evaluates to 0.9. In the double case I’ve only done a single calculation and already I have enough error to show up.
When coding in Java working with BigDecimal is awkward because it’s a class rather than a primitive. That means you can’t use your normal +, *, - operators and have to use the class’s API instead.
1 If you haven’t seen Office Space yet (http://mng.bz/c6o8), you have a real treat ahead of you.
www.it-ebooks.info
170 |
|
|
|
|
CHAPTER 7 The Spring framework |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
@Service |
|
|
<<interface>> |
|
@Repository |
|
JdbcTemplate |
|||
|
AccountService |
|
|
AccountDAO |
|
JdbcAccountDAO |
|
|
|||
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Account |
|
|
|
|
Embedded |
||
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
DB |
|
|
|
|
|
|
|
|
|
|
|
Figure 7.2 A simple account management application. Transactions are demarcated in the service layer. The persistence layer consists of a single DAO class that implements an interface and uses the Spring JdbcTemplate to access an embedded database.
Because Groovy has operator overloading, however, none of that is necessary. I can simply declare the balance to be a BigDecimal, and everything else just works, even if I use the Account class from Java.
One additional comment about the Account: at the moment no constraints are being applied to ensure that the balance stays positive. This is as simple as I can make it, just for exposition purposes.
The overall design for using the Account class is shown in figure 7.2. This is a very simple form of a layered architecture, with transactional support in the service layer and a persistence layer that consists of an interface and a DAO class, discussed shortly.
The persistence layer follows the normal Data Access Object design pattern. The next listing shows a Java interface, called AccountDAO, written in Java.
Listing 7.2 The AccountDAO interface, in Java
package mjg.spring.dao;
import java.util.List;
import mjg.spring.entities.Account;
public interface AccountDAO {
int createAccount(double initialBalance); Account findAccountById(int id); List<Account> findAllAccounts();
void updateAccount(Account account); void deleteAccount(int id);
}
The interface contains typical methods for transferring Account objects to the database and back. There’s a method to create new accounts, update an account, and delete an account; a method to find an account by id; and one to return all the accounts.
The implementation of the interface, using a Groovy class called JdbcAccountDAO, works with the JdbcTemplate from Spring. Rather than show the whole class (which is available in the book source code), let me present just the structure and then emphasize the Groovy aspect afterward. An outline of the class is shown in the following listing.
www.it-ebooks.info
A Spring application |
171 |
Listing 7.3 Implementing the AccountDAO using JdbcTemplate, in Groovy
@Repository
class JdbcAccountDAO implements AccountDAO { JdbcTemplate jdbcTemplate
@Autowired
JdbcAccountDAO(DataSource dataSource) { jdbcTemplate = new JdbcTemplate(dataSource)
}
int createAccount(double initialBalance) { ... } void updateAccount(Account account) { ... }
void deleteAccount(int id) { ... }
Account findAccountById(int id) {
String sql = "select * from accounts where id=?" jdbcTemplate.queryForObject(sql,
accountMapper as RowMapper<Account>, id)
}
Template that simplifies JDBC
Closure coercion implementing the interface
List<Account> findAllAccounts() {
String sql = "select * from accounts" jdbcTemplate.query(sql, accountMapper as RowMapper<Account>)
}
def accountMapper = { ResultSet rs, int row ->
new Account(id:rs.getInt('id'),balance:rs.getDouble('balance'))
}
}
The various query methods take an argument of type RowMapper<T>, whose definition is
public interface RowMapper<T> {
T mapRow(ResultSet rs, int rowNum) throws SQLException
}
When you execute one of the query methods in JdbcTemplate, Spring takes the ResultSet and feeds each row through an implementation of the RowMapper interface. The job of the mapRow method is then to convert that row into an instance of the domain class. The normal Java implementation would be to create an inner class called, say, AccountMapper, whose mapRow method would extract the data from the ResultSet row and convert it into an Account instance. Providing an instance of the AccountMapper class to the queryForObject method would then return a single Account. The same instance can be supplied to the query method, which then returns a collection of Accounts.
This is exactly the type of closure coercion demonstrated in chapter 6. A variable called accountMapper is defined and assigned to a closure with the same arguments as the required mapRow method. The variable is then used in both the findAccountById and findAllAccounts methods.
www.it-ebooks.info
172 |
CHAPTER 7 The Spring framework |
There are two uses for Groovy here:
1A Groovy class implemented a Java interface, which makes integration easy and simplifies the code.
2Closure coercion eliminated the expected inner class.
In the example in the book source code I also included the service class referenced in figure 7.2. It uses Spring’s @Transactional annotation to ensure that each method operates in a required transaction. There is nothing inherently Groovy about it, so again I’ll just show an outline of the implementation in the next listing.
Listing 7.4 A portion of the AccountService class in Java
@Service |
|
Declarative transactional |
|||
|
|||||
@Transactional |
|
|
|||
|
|
behavior |
|||
public class AccountService { |
|
||||
|
|
|
|
||
@Autowired |
|
|
|
Injecting |
|
private AccountDAO dao; |
|
|
|
||
|
|
|
the DAO |
public double getAccountBalance(int id) { ... }
public double depositIntoAccount(int id, double amount) { ... } public double withdrawFromAccount(int id, double amount) { ... }
public boolean transferFunds(int fromId, int toId, double amount) { Account from = dao.findAccountById(fromId);
Account to = dao.findAccountById(toId); from.withdraw(amount); to.deposit(amount); dao.updateAccount(from); dao.updateAccount(to);
return true;
}
}
The @Autowired annotation is used by Spring to plug in (inject) an instance of a class implementing the AccountDAO interface into the service class. See the Spring documentation2 for more details on autowiring.
The service implementation is in Java mostly because there’s no great advantage to implementing it in Groovy, though I could easily have done so.
The last piece of the puzzle is the Spring bean configuration file. The configuration in the book source code uses a combination of XML and a component scan for the repository and service classes. Again, nothing in it uses Groovy, so I won’t present it here. For the record, the sample uses Spring’s <embedded-database> tag to set up a sample H2 database in memory that is reinitialized on each run. The rest is as described.
Returning now to Groovy, I want to show the Gradle build file in the next listing.
2 http://mng.bz/m9M3
www.it-ebooks.info
A Spring application |
173 |
Listing 7.5 The Gradle build file for the account application
apply plugin:'groovy' apply plugin:'eclipse'
repositories { mavenCentral()
}
def springVersion = '3.2.2.RELEASE' def spockVersion = '0.7-groovy-2.0'
dependencies {
compile "org.codehaus.groovy:groovy-all:2.1.5"
compile "org.springframework:spring-context:$springVersion" compile "org.springframework:spring-jdbc:$springVersion" runtime "com.h2database:h2:1.3.172"
runtime "cglib:cglib:2.2"
testCompile "org.springframework:spring-test:$springVersion" testCompile "org.spockframework:spock-core:$spockVersion" testCompile "org.spockframework:spock-spring:$spockVersion"
}
The build file is typical of projects presented in this book so far. It declares both the Groovy and Eclipse plugins. It uses Maven central for the repository. The dependencies include Groovy and Spock, as usual. Spring is added by declaring the springcontext and spring-jdbc dependencies. Those dependencies wind up adding several other Spring-related JARs. The h2database dependency is used for the H2 driver needed by the embedded database.
One interesting addition is the spock-spring dependency. Spring includes a powerful testing framework of its own, which is based on JUnit and automatically caches the Spring application context. The spock-spring dependency lets Spock tests work with the Spring testing context.
The first test class is a Spock test for the JdbcAccountDAO. The following listing shows some of the tests from the complete set.
Listing 7.6 Spock tests for the JdbcAccountDAO implementation
import spock.lang.Specification;
@ContextConfiguration("classpath:applicationContext.xml")
@Transactional
class JdbcAccountDAOSpec extends Specification { @Autowired
JdbcAccountDAO dao
def "dao is injected properly"() { expect: dao
}
def "find 3 accounts in sample db"() { expect: dao.findAllAccounts().size() == 3
}
www.it-ebooks.info
174 |
CHAPTER 7 The Spring framework |
def "find account 0 by id"() { when:
Account account = dao.findAccountById(0)
then: account.id == 0
account.balance == 100.0
}
// tests for other methods as well
}
The @ContextConfiguration annotation tells the test runner how to find the Spring bean configuration file. Adding @Transactional means that each test runs in a required transaction that (and this is the cool part) rolls back automatically at the end of each test, implying that the database is reinitialized at the beginning of each test. The DAO is autowired into the test class. The individual tests check that all the methods in the DAO work as expected.
The next listing shows the tests for the service class, which includes using the old method from Spock described in chapter 6 on testing.
Listing 7.7 Spock tests for the service class
import spock.lang.Specification
@ContextConfiguration("classpath:applicationContext.xml")
@Transactional
class AccountServiceSpec extends Specification { @Autowired
AccountService service
def "balance of test account is 100"() {
expect: service.getAccountBalance(0) == 100.0
}
// ... other tests as necessary ...
def "transfer funds works"() { when: service.transferFunds(0,1,25.0)
then: service.getAccountBalance(0) ==
old(service.getAccountBalance(0)) - 25.0 service.getAccountBalance(1) ==
old(service.getAccountBalance(1)) + 25.0
}
}
As before, the annotations let the Spock test work with Spring’s test framework, which caches the application context. I used the old operation from Spock to check changes in the account balance after a deposit or withdrawal. No other additions are needed to use Spock with the Spring test context.
This application, though simple, illustrates a lot of Spring’s capabilities, from declarative transaction management to autowiring to simplified JDBC coding to effective
www.it-ebooks.info