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

Accessing Google Chart Tools

23

The result of all this manipulation is actually a string, not a URL. Before converting it to a URL, let me first verify that the process worked. Normally this would require a test, as discussed extensively in chapter 6 on testing. Here, however, I’ll just use the Groovy assert keyword, which takes a boolean expression as an argument. If the expression is true, nothing is returned, but if not, you get the error printed to the console. In this case I’ll use the contains method from the Map interface to check that each of the entries from the params map appears in the query string in the proper format:

params.each { k,v ->

assert qs.contains("$k=$v")

}

THE ASSERT KEYWORD Groovy asserts are an easy way to verify correctness. An assert returns nothing if the expression is true, and prints a detailed error message if it’s not.

One of the advantages of the join method is that you don’t have to worry about accidentally adding an ampersand at the beginning or end of the string. It only adds the separator internally.

Note also that this is a case where the parentheses (on the join method) are needed. In Groovy, if you leave off the parentheses when calling a method with no arguments the compiler assumes you are asking for the corresponding getter or setter method. Because I want the join() method (and not getJoin(), which doesn’t exist), I need the parentheses.

2.2.2Transmitting the URL

The Groovy JDK adds the toURL() method to the String class. As you might imagine, this method converts an instance of java.lang.String into an instance of java.net.URL.

The Groovy JDK

Groovy adds many helpful methods to existing Java library classes. Many, many times I’ve found methods added to, say, String, Date, or Collection that I always wished were in Java all along. The set of methods added by Groovy is known as the Groovy JDK and has its own set of JavaDocs. The Groovy JDK documentation is available via a link from the Groovy home page.

The Groovy JDK is discussed in more detail in chapter 3.

To send an HTTP GET request to a URL and retrieve the results, convert the string to a URL and invoke another Groovy JDK method, the getText() method, added to java.net.URL. In other words, the data on a web page can be retrieved from this code:

url.toURL().text

www.it-ebooks.info

24 CHAPTER 2 Groovy by example

Here I’m deliberately using the text property of the URL class, knowing that the effect will be to invoke the getText() method. There’s nothing wrong with actually calling getText, but this is more idiomatic Groovy.

Normally this would be exactly the code I want, and I use this technique in some of the examples in the chapters on web services, but in this particular case the result isn’t text. Google Chart takes the URL generated here and returns a binary image, so converting it to text isn’t very helpful.

GROOVY PROPERTIES Accessing properties in Groovy automatically invokes the associated getter or setter method.

Next I’ll build a Swing user interface that includes the image in a javax.swing

.ImageIcon. This will give me a chance to illustrate a builder, which is a great illustration of Groovy metaprogramming.

2.2.3Creating a UI with SwingBuilder

In Groovy every class has a metaclass. A metaclass is another class that manages the actual invocation process. If you invoke a method on a class that doesn’t exist, the call is ultimately intercepted by a method in the metaclass called methodMissing. Likewise, accessing a property that doesn’t exist eventually calls propertyMissing in the metaclass. Customizing the behavior of methodMissing and propertyMissing is the heart of Groovy runtime metaprogramming.

Groovy metaprogramming is a large subject, but here I’ll demonstrate one of its helpful results: the creation of builder classes. In a builder, the call to methodMissing does something specific for that type of builder.

Here I’ll illustrate a Swing builder. This is a class that intercepts names of components and constructs a Swing user interface out of the results. This is actually easier to demonstrate than to explain. I’ll start, however, by adding some imports to the Google Chart script I’ve been constructing so far:3

import java.awt.BorderLayout as BL import javax.swing.WindowConstants as WC import groovy.swing.SwingBuilder

import javax.swing.ImageIcon

Automatic imports

You may have noticed that I haven’t yet needed any import statements at all. Java automatically imports the java.lang package. Groovy imports java.lang, as well as java.util, java.io, java.net, groovy.lang, groovy.util, java.math.BigInteger, and java.math.BigDecimal.3

3That’s another one of the “Duh! Why didn’t we do that all along?” type of revelations that Java developers get all the time when they first learn Groovy. Why is it we only import java.lang in Java programs? Why not import lots of typical packages? Wouldn’t that make coding easier? Groovy says yes.

www.it-ebooks.info

Accessing Google Chart Tools

25

In this script I’m importing three classes from the Java standard library. The first two imports use the as operator to build an alias for the respective classes. That way the code that uses BorderLayout and WindowConstants can just write BL or WC instead. I’m also adding in the ImageIcon class, which will hold the image returned by Google Chart. The import from the Groovy library is SwingBuilder, which will be used to construct the Swing UI.

THE AS KEYWORD The as keyword has several uses, one of which is to provide an alias for imported classes. The as keyword corresponds to the asType method, which was added to java.lang.Object as part of the Groovy JDK.

In the case of SwingBuilder you invoke methods that don’t exist on the builder but that are translated to the corresponding Swing API. For example, by calling the frame method you’re actually instantiating the JFrame class. Giving it a map-like argument of visible:true corresponds to calling the setVisible method with a true argument.

Here’s the code that uses the builder. Each method not in SwingBuilder is translated to the proper method call on the Swing library class:

SwingBuilder.edt {

frame(title:'Hello, World!', visible:true, pack: true, defaultCloseOperation:WC.EXIT_ON_CLOSE) {

label(icon:new ImageIcon("$base$qs".toURL()), constraints:BL.CENTER)

}

}

The edt method on SwingBuilder builds a GUI using the event dispatch thread. It takes a closure as an argument, and this is where the fun starts. The first statement inside the closure is a call to the frame method, but the fact is, there’s no frame method in SwingBuilder. The builder’s metaclass intercepts that call (via methodMissing) and interprets it as a request to instantiate the javax.swing.JFrame class. The frame method here lists a series of map entries, which are intended to supply values for the title, visibility, and close operation on the JFrame. The builder interprets them as calls to setTitle, setVisible, and setDefaultCloseOperation on the

JFrame instance.

After the parentheses there’s another closure. That’s interpreted to mean I’m about to supply components that will be added to the JFrame instance. The next call is to the label method, which of course doesn’t exist. The Swing builder knows to generate a JLabel instance as a result, call its setIcon method with a new ImageIcon holding the image returned by Google Chart, and place the JLabel in the center of a

BorderLayout.

Finally, after the frame closure I invoke the pack method on JFrame to make the resulting GUI just big enough to hold the image. The next listing contains the complete script (without the asserts, just to keep the listing short).

www.it-ebooks.info

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