Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Kenneth A. Kousen - Making Java Groovy - 2014.pdf
Скачиваний:
50
Добавлен:
19.03.2016
Размер:
15.36 Mб
Скачать

Building and testing web applications

This chapter covers

Groovy servlets and ServletCategory

Groovlets

Unit and integration testing of web apps

The Groovy killer app, Grails

While Java on the desktop has its adherents, Java found a true home on the server side. Java’s growth and adoption in the early days neatly follow that of the web itself. It’s a rare Java developer who hasn’t at least worked on a web application.

In this chapter I’m going to look at modern web application development and where Groovy can make the process simpler and easier. Sometimes Groovy just simplifies the code. Other times it provides helpful testing tools, like Gradle and HTTPBuilder. Finally, there’s the most famous framework in the Groovy ecosystem, Grails. I’ll review them all and try to place them in the overall context of web applications.

Figure 10.1 is a guide to the technologies discussed in this chapter.

257

www.it-ebooks.info

258

CHAPTER 10 Building and testing web applications

 

Spring web

Gradle

 

Java

integration

Java +

mocks

testing

testing

Groovy

 

 

 

 

testing

Groovy

Servlet

Groovlets

 

language

category

 

 

 

Groovy

HttpBuilder

Grails

projects

 

 

Figure 10.1 Guide to the technologies in this chapter. Spring provides mock objects for testing that are also used in Grails. Using plugins and some configuration, Gradle builds can do integration testing of web applications. The ServletCategory class makes session, request, and other objects easier to use. Groovlets are a quick way to build simple applications. Finally, the HTTPBuilder project provides a programmatic web client, and Grails applications use Groovy DSLs and elegant metaprogramming to combine Spring and Hibernate in a standard convention-over-configuration framework.

10.1 Groovy servlets and ServletCategory

Groovy doesn’t add a lot to basic servlet development, but the standard library does provide a category class that illustrates what Groovy’s metaprogramming can do. The following listing shows a trivial servlet, HelloGroovyServlet.groovy, part of a web application implemented in Groovy.

Listing 10.1 A simple servlet implemented in Groovy

class HelloGroovyServlet extends HttpServlet {

void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

resp.writer.print 'Hello from a Groovy Servlet!'

}

}

Other than the normal Groovy simplifications (omitting the word public, lack of semicolons, use of writer rather than getWriter(), and the optional parentheses on print), this isn’t much different from a Java implementation. Use Groovy if you prefer the slightly shorter code, but really the choice of language is a matter of style.

What Groovy does provide is a category class to simplify the code even further. Category classes are an example of Groovy’s metaprogramming capabilities. They show how to add methods to existing classes in a specified block of code, unlike using the metaclass object to add them everywhere in your program. If you ever wanted to understand categories, ServletCategory is a great, extremely simple, useful example.

www.it-ebooks.info

Groovy servlets and ServletCategory

259

Figure 10.2 The GroovyDocs for ServletCategory. Each method is static and is added to the class listed in the first argument.

CATEGORIES Use a Groovy category to add methods to existing classes when you only need those methods under specific circumstances. Category methods are only available in a use block.

Figure 10.2 shows a sample of the GroovyDocs for the groovy.servlet.ServletCategory class.

A Groovy category consists of static methods having one or more arguments. The first argument to the method is the class that receives the method. In ServletCategory there are only four methods, with lots of overloads (see table 10.1).

Table 10.1 The ServletCategory methods for different scopes

Method Name

First Argument

 

 

get(arg, String key)

ServletContext, HttpSession,

 

ServletRequest, PageContext

getAt(arg, String key)

Same as above

putAt(arg, String key, Object value)

Same as above

set(arg, String key, Object value)

Same as above

 

 

www.it-ebooks.info

260

CHAPTER 10 Building and testing web applications

See a pattern? The job of this category is to make it easy to add attributes at page scope (PageContext), request scope (ServletRequest), session scope (HttpSession), and application scope (ServletContext). Remember that in Groovy all operators correspond to methods. In this case, the get and set methods correspond to the dot operator, and the getAt and putAt methods implement the array subscript operator. Before I show an example, take a look at a portion of the actual implementation class, groovy.servlet.ServletCategory, in the following listing, implemented in Java.

Listing 10.2 Methods for HttpSession from groovy.servlet.ServletCategory

public class ServletCategory {

public static Object get(HttpSession session, String key) { return session.getAttribute(key);

}

...

public static Object getAt(HttpSession session, String key) { return session.getAttribute(key);

}

...

public static void set(HttpSession session, String key, Object value) { session.setAttribute(key, value);

}

...

public static void putAt(HttpSession session, String key, Object value) { session.setAttribute(key, value);

}

}

The first interesting thing to note is that this class is written in Java (!), even though it’s being used in Groovy. When overloading operators, Groovy doesn’t care which language you use to implement the methods, only that you use the operators that delegate to the methods in Groovy. In this case, I don’t even plan to use the methods directly. Instead, I’m using the dot operator and/or the array subscript notation to invoke them implicitly.

The other important detail here is that all the methods are delegating to either the getAttribute or setAttribute method. The effect is that either the dot operator or the subscript operator can be used to add attributes to the page, request, session, or application scope.

SERVLETCATEGORY Whether you use ServletCategory or not, its combination of metaprogramming and operator overloading make it an excellent example of how Groovy helps Java.

www.it-ebooks.info

Groovy servlets and ServletCategory

261

Categories in Groovy 2.0

Groovy 2.0 introduced an alternative syntax for defining categories. In the ServletCategory discussed in this section, the category class contains static methods whose first argument is the class being modified. In the new notation you can use annotations and instance methods instead.

As an example, consider formatting numbers as currency. The java.text.NumberFormat class has a method called getCurrencyInstance, which has both a no-arg method that formats for the current locale and an overloaded version that takes a java.util.Locale argument. The classic way to add an asCurrency method to Number that employs the currency formatter is

import java.text.NumberFormat

class CurrencyCategory {

static String asCurrency(Number amount) { NumberFormat.currencyInstance.format(amount)

}

static String asCurrency(Number amount, Locale loc) { NumberFormat.getCurrencyInstance(loc).format(amount)

}

}

use(CurrencyCategory) {

def amount = 1234567.89012 println amount.asCurrency()

println amount.asCurrency(Locale.GERMANY)

println amount.asCurrency(new Locale('hin','IN'))

}

The new way to implement a category uses the @Category annotation, which takes the class to be modified as an argument. Then instance methods are used inside the category, and the this reference refers to the object where the category is invoked. The analogous implementation for the currency category is

import java.text.NumberFormat

@Category(Number)

class AnnotationCurrencyCategory { String asCurrency() {

NumberFormat.currencyInstance.format(this)

}

String asCurrency(Locale loc) { NumberFormat.getCurrencyInstance(loc).format(this)

}

}

Number.mixin AnnotationCurrencyCategory def amount = 1234567.89012

println amount.asCurrency()

println amount.asCurrency(Locale.GERMANY) println amount.asCurrency(new Locale('hin','IN'))

www.it-ebooks.info

262

CHAPTER 10 Building and testing web applications

(continued)

Note also the use of the mixin method to add the category to the Number class.

Presumably, if the ServletCategory was being implemented now, it would use the annotation approach. The result is the same either way, of course.1

An example will make this clear. The next listing shows a class called HelloNameServlet, implemented in Groovy, which receives a name parameter and replies with the standard welcome.1

Listing 10.3 The HelloNameServlet class, which uses the ServletCategory

import groovy.servlet.ServletCategory;

import javax.servlet.ServletException import javax.servlet.http.HttpServlet

import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse

class HelloNameServlet extends HttpServlet {

 

void doGet(HttpServletRequest request, HttpServletResponse response)

 

 

throws ServletException, IOException {

Make category

Get session

 

def session = request.session

 

 

 

methods available

from request

 

use (ServletCategory) {

 

 

 

 

 

 

 

 

 

 

request.name = 'Hello, ' +

 

 

Delegate to get/set and

 

 

(request.getParameter('name') ?: 'World')

 

 

 

 

 

 

session['count'] = (session.count ?: 0) + 1

 

 

getAt/putAt methods

}

request.getRequestDispatcher('hello.jsp')

.forward(request,response)

}

}

This class works with attributes in both the request and the session. After getting the session from the request (which is standard “property access means get method” style, not the category), the use block defines the region where the category is active. Inside the use block, a name attribute is added to the request using the dot notation, whose value is either supplied by the user in the form of a parameter, or consists of the default value World. Next, a count attribute is placed in the session; its value is either incremented from its existing value or set to 1 if it doesn’t already exist.

The test class, HelloNameServletTest, is shown in the next listing. It uses the Spring API mock objects to test the doGet method both with and without a supplied name.

Listing 10.4 The HelloNameServletTest class, which uses Spring’s mock objects

import static org.junit.Assert.*;

import org.junit.Test;

import org.springframework.mock.web.MockHttpServletRequest;

1 The book source code includes the two ways of doing the currency category as well as a test case.

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]