Gr8 Gr8Conf.US Was Gr8

This week I attended Gr8Conf US in Minneapolis. I did a Groovy workshop for Java developers, gave my Making Java Groovy talk, gave a talk on Grails testing, and even managed to throw in an Advanced Groovy Tips and Tricks talk at the last minute when Guillaume Laforge was unable to travel.

(Guillaume said he burned his hand rather badly while cooking. I prefer to believe that he was defending a bunch* of children from a horde of vicious biker ninjas (or possibly Scala developers) intent on world domination. That fits my mental image of him much better. He may look like Clark Kent, but when attacked by a horde of vicious biker ninjas (or possibly Scala developers) he transforms into — well, you know. Seriously, Guillaume, get well soon. You were missed.)

*What is the collective noun for children, anyway? Bunch? Herd? I like “mess”, as in “a mess of children.” Seems appropriate somehow.

This was the third Gr8Conf I’ve attended, and the quality has improved each year. Shaun Jurgemeyer did a great job of organizing, both in the quality and quantity of talks. One thing that was different this year was the Target Hackathon, which was held Sunday evening after the workshops and involved building an application using the Target API. I had what I thought was a good idea, but simply ran out of time, so I’ll save it for next year.

Later I saw pictures of the venue where the Hackathon was held, complete with ping-pong table and outdoor chess set. Like a typical developer, I had my head buried in my laptop the whole time and missed all that. I did manage to sit next to the eventual winner, Todd Miller, who turned out to be a seriously cool guy.

I don’t want to go through the talks I attended one by one, but I do have a few observations:

  • After sitting through Cedric Champeau’s workshop on AST transformations, I have to say I still find them confusing, but at least now my confusion has boundaries. I expect I’ll need to sit down and really dig into the associated chapter in Groovy in Action to understand them.
  • Several talks brought up the new capabilities planned for Grails 2.3, especially involving RESTful web services. I’m looking forward to them, too. What I didn’t expect was the backlash against HATEOAS (Hypermedia As The Engine Of Application State). On the NFJS tour I guess I’ve been hanging out with too many RESTafarians* lately. Peter Ledbrook told me that even David Heinemeier Hansson doesn’t see the benefit of hypermedia, though he’s hardly shy about speaking his mind or going against the popular wisdom. I spent months getting hypermedia to work for my REST chapter in Making Java Groovy**. I still think that was a good investment in time and effort, especially since there are very few good hypermedia examples out there, but maybe I shouldn’t worry so much about the fact that the word “hypermedia” doesn’t even appear in the JAX-RS 2.0 specification.
  • I had no idea how much the tooling in the JavaScript space has evolved. I’d never heard of Grunt, or Bower, or Yeoman, or any of the other tools that come from the nodejs ecosystem. I did hear one good quote, though I can’t remember who said it (probably Zan Thrash but I’m not sure), saying these tools “bring all the joys of downloading the internet to the JavaScript space.” I suppose it seems odd spending so much time on JavaScript at a Groovy conference, but that’s the web world we now live in.
  • I wish I could have seen Luke Daley’s Ratpack presentation, especially after he helped me get the build running at UberConf. Dan Woods managed to implement FOAAS on Ratpack (check it out, but it’s arguably NSFW). At the speaker dinner (thanks, Shaun!), Luke claimed that this was only the second Ratpack app in production, with the first being the Ratpack web site itself. 🙂
  • I also wish I could have attended Marco Vermeulen’s talk on GVM. I use GVM all the time and recommend it everywhere, especially if you ever have to change Groovy or Grails versions easily. I finally got to meet Marco, and it turned out he even likes my book***. He’s yet another great guy in the Groovy community. Honestly, the extraordinary friendliness and humility of the developers in the Groovy ecosystem is one of its best features.

*Yah mon, dey be callin’ demselves RESTafarians, which shows much more of a sense of humor than I originally thought they had.

**Are you impressed I made it this far before mentioning my book, Making Java Groovy? I know I am. I just uploaded the revised preface and appendices after the tech review, so everything is still on schedule for an early September release.

***Yeah, that’s probably a humblebrag. Let me turn it into a real brag. At both Gr8Conf and UberConf I had several people tell me how much they liked the book, which feels especially weird (oops, there’s the definitive humblebrag keyword again) because it’s not quite in production yet. Still, that was great to hear.

I feel obligated to do something technical in my blog posts, so let me mention a technique I use a lot and can implement with a tiny bit of metaprogramming. Whenever I need to access a RESTful web service that requires a set of parameters on a query string, I assemble them from a Groovy map.

For example, The random.org web site has a service that generates truly randome numbers “via atmospheric noise,” as they say on the site. To generate a set of random integers base URL is ‘www.random.org/integers’ and you add a series of parameters to specify what you want. In their main example, they ask for 10 numbers between 1 and 6, in 10 columns, base 10, in plain format using a new generator.

Here’s a quick Groovy script to call it:

String base = 'http://www.random.org/integers/?'
def qs = 
    [num:10, min:1, max:6, col:10, base:10, format:'plain', rnd:'new']
        .collect{ k,v -> "$k=$v" }.join('&')
def nums = "$base$qs".toURL().text.split()

I put all the query parameters in a map, then use the collect method to produce a list of “key=value” pairs based on the map entries, and join them using an ampersand. Then I use the toURL method from the String class in the Groovy JDK to turn the address into an instance of java.net.URL, and the text property of the URL class to invoke the getText method. The result is something like:

[4, 1, 4, 6, 3, 3, 1, 4, 3, 3]

I’ve been writing code like that for years, but some time ago the brilliant Paul King told me I could simplify it. It turns out that the toString method in Map.Entry returns “key=value”, so I can write instead:

[num:10, min:1, max:6, col:10, base:10, format:'plain', rnd:'new']
        .collect{ it }.join('&')

He’s right, of course. I still use the more verbose version in presentations to Groovy newcomers, because it’s a bit clearer, but I normally use the simpler one in my own work.

It occurs to me that I can use Groovy metaprogramming to simplify this even further, if I plan to use that construct a lot. Here I add a toQS method to the Map interface.

Map.metaClass.toQS = { -> delegate.collect { it }.join('&') }

def qs = 
    [num:10, min:1, max:6, col:10, base:10, format:'plain', rnd:'new'].toQS()
assert qs == 'num=10&min=1&max=6&col=10&base=10&format=plain&rnd=new'

I get the metaclass from the java.util.Map class* and add a toQS method by assigning it to a closure. Since my method doesn’t take any arguments, I used a zero-argument closure. The delegate property inside the closure refers to the map the closure was invoked on, and the rest is as before.

*Yes, I know java.util.Map is an interface, but it appears as a class in the Groovy JDK.

The final version of the demo script is therefore:

Map.metaClass.toQS = { -> delegate.collect { it }.join('&') }

String base = 'http://www.random.org/integers/?'
def qs = 
    [num:10, min:1, max:6, col:10, base:10, format:'plain', rnd:'new'].toQS()
println "$base$qs".toURL().text.split()

There you have it. Now that I think about it, I should probably fork the Groovy project and submit a pull request for it. I’ll probably have to talk to Paul or Guillaume about that.

One last thing: what kind of motorcycle would vicious biker ninjas drive? Harley’s would be way too loud. I presume it would be one of those cool machines like in Tron, all in black.

A Groovy Chuck Norris Script

This week I’m at UberConf (http://uberconf.com), a truly alpha-geek experience with sessions morning, afternoon, and evening. On Tuesday I did a day-long tutorial on Groovy for Java developers, which was really fun. I love teaching Groovy to existing Java developers. Sometimes they get tears in their eyes at how much easier life can be. 🙂 Wednesday I had a Spock workshop followed by a Grails workshop. Yesterday I did my Bayes’ Rule talk (“Bayes’ Rule Says You’ll Attend This Talk”), and today I’m doing my “Managing Your Manager” talk and my “Making Java Groovy” talk again.

Making Java Groovy has now moved into the production phase. So far this means discussing art work with the illustrators and trying to explain to them what I actually meant with my limited attempts at using a drawing tool.

I’ve been working on this book for nearly five years, and that means some of the earliest chapters needed some serious updating recently. When I started I think Groovy had just released version 1.6, so it’s changed versions at least four times during the writing process. Groovy 2.2 may even come out when the book shows up in print, at which point I’ll have to go back to the GitHub repo and update all the Gradle build files again.

One of the earliest chapters I wrote was the “Groovy by Example” chapter. In it I used the Google Chart API (which is now deprecated but still available) and an early version of my Groovy Baseball application. I really wanted to update all that to newer examples, but there simply wasn’t time, especially given that they all still worked correctly.

Still, I did take the time to write another example, even if it turned out to be too late to add it to the book. I’d like to show it here, because it’s simple but still pretty interesting, which is a good combination.

In many of my presentations (including one I’ll be doing later today), I like to access the ICNDB web site as an example of a RESTful web service that serves up JSON data. That’s ICNDB, as in the Internet Chuck Norris Database. ICNDB is a RESTful service in name only; it doesn’t do content negotiation (it doesn’t even set the “Content-Type” header correctly, a fact I discovered when I made an Android front end for it — see the ICNDB app in the Google Play store) and it only supports GET requests.

(Mandatory jokes: wouldn’t a RESTful service that only supports GET requests be called a GETful service? And if it’s stateless, wouldn’t that make it a FORGETful service? Insert rimshot here.)

The Groovy JDK makes it trivially easy to access a URL with a GET request. Groovy adds a toURL method to the String class, which converts a String into an instance of java.net.URL, and a getText method to the URL class, which returns the response as a String. Calling it is as simple as:

import groovy.json.JsonSlurper

String base = 'http://api.icndb.com/jokes/random?limitTo=[nerdy]'
def json = new JsonSlurper().parseText(base.toURL().text)
println json?.value?.joke

Following the normal Groovy idiom, I invoke getText by accessing the text property of the URL. Then I use a JsonSlurper to parse the result, which essentially converts it into a nested map-based data structure. The JSON object has a value property that holds another JSON object, which stores the actual joke in a property called joke. I don’t really need the safe de-reference operator here, but it doesn’t hurt.

The results are similar to:

Chuck Norris can unit test entire applications with a single assert.

The interesting question then becomes, how do I turn this into a client-side application with a graphical interface?

The Groovy API includes a so-called “builder” class called SwingBuilder, which makes Swing development almost (but not quite) cool. It even has easy ways to handle threading issues, so that I can access the service off of the event dispatch thread, but update the GUI back on it. The key is in the doOutside and doLater methods. The former allows you to do work without locking up the GUI, while the latter is where you update the interface.

(The best discussion of SwingBuilder I’ve ever seen is contained in Griffon in Action, by Andres Almiray, Danno Ferrin, and Jim Shingler.)

Here’s the whole script, which I’ll explain afterwards. In the book source code (just because I couldn’t put the app in the book doesn’t mean I couldn’t add it to the repo), this script is called icndb_with_label_and_button.groovy.

import groovy.json.JsonSlurper
import groovy.swing.SwingBuilder

import java.awt.BorderLayout as BL
import java.awt.Color
import java.awt.Font

import javax.swing.WindowConstants as WC

String startHTML = "<html><body style='width: 100%'>"
String endHTML = '</body></html>'

String base = 'http://api.icndb.com/jokes/random?limitTo=[nerdy]'
def slurper = new JsonSlurper()

new SwingBuilder().edt {
    frame(title:'ICNDB', visible: true, pack: true,
        defaultCloseOperation:WC.EXIT_ON_CLOSE) {
        panel(layout:new BL(), preferredSize:[300, 250], background: Color.WHITE) {
            label('Welcome to ICNDB', 
                constraints:BL.NORTH,
                font: new Font('Serif', Font.PLAIN, 24), 
                id: 'label')
            button('Get Joke', constraints:BL.SOUTH,
                actionPerformed: {
                    doOutside {
                        def json = slurper.parseText(base.toURL().text)
                        doLater { 
                            label.text = "${startHTML}${json?.value?.joke}${endHTML}" 
                        }
                    }
                }
            )
        }
    }
}

A couple of the import statements use the as operator to create aliases. That is, I can use WC in the script to refer to javax.swing.WindowConstants, and BL to represent java.awt.BorderLayout. That’s an interesting but underused feature of the as operator.

I want to add the joke to a JLabel, which supports HTML. Therefore, I defined strings to surround the HTML when I put the joke in the label.

The SwingBuilder class has an edt method which lets me operate on the event dispatch thread when building the GUI. Then terms (actually, method calls) like frame, panel, label, and button create instances of JFrame, JPanel, JLabel, and JButton from the Swing API. The attributes, like visible:true and title:'ICNDB' invoke the setVisible and setTitle methods, respectively.

Arguably the best part, though, is the actionPerformed property. If you’ve ever done Swing development, you know that clicking a JButton generates an ActionEvent. In order to capture the event you need an ActionListener, which has a single method called actionPerformed. In regular Swing development, the result is usually an inner class (or even an anonymous inner class) that implements the interface and updates the GUI. You use an inner class because the inner class is able to access the private attributes of the outer class, and when I used to do Swing development I normally made the labels and buttons attributes of my GUI class.

Here, though, I don’t need an inner class at all. Instead I assign the actionPerformed property to a closure, and I’m finished. One of the nicest uses of closures is to eliminate anonymous inner classes this way.

Inside the closure I use the doOutside method to access the service. Then I get back onto the EDT using doLater and update the GUI. By giving the label an id attribute, I was able to access it inside the doLater closure using the value of the id.

The result is something like:
icndb_label_with_button

That’s all there is to it. I’m not thrilled with the HTML parts, though, so I also implemented the script using a text area instead. The resulting script is in the file icndb_with_textarea_and_button.groovy:

import groovy.json.JsonSlurper
import groovy.swing.SwingBuilder

import java.awt.BorderLayout as BL
import java.awt.Color
import java.awt.Font

import javax.swing.WindowConstants as WC

String base = 'http://api.icndb.com/jokes/random?limitTo=[nerdy]'
def slurper = new JsonSlurper()

new SwingBuilder().edt {
    frame(title:'ICNDB', visible: true, pack: true,
        defaultCloseOperation:WC.EXIT_ON_CLOSE) {
        panel(layout:new BL(), preferredSize:[300, 250], background: Color.WHITE) {
            scrollPane {
                textArea('Welcome to ICNDB', 
                    constraints:BL.NORTH,
                    font: new Font('Serif', Font.PLAIN, 24),
                    lineWrap: true, wrapStyleWord: true, editable: false,
                    id: 'textArea')
            }
            button('Get Joke', constraints:BL.SOUTH,
                actionPerformed: {
                    doOutside {
                        def json = slurper.parseText(base.toURL().text)
                        doLater {
                            textArea.text = json?.value?.joke
                        }
                    }
                }
            )
        }
    }
}

I wrap the text area in a scroll pane, but other than that it’s essentially the same code. The result now looks like:
icndb_with_textarea_and_button

So that’s it: a small, but hopefully non-trivial application that demonstrates Groovy capabilities including builders, thread handling, RESTful web services, and even the as operator. Have fun with it.

In the meantime, I’m ignoring the take down notice I received from Chuck Norris’s lawyers about my ICNDB app in the Play store. Sigh.

Categories, old and new, and status of Making Java Groovy

My book, Making Java Groovy, is almost finished. I mean, I’m done, except that I’m not.

(Picture Michael Corleone in “Godfather, Part III”: “Just when I thought I was out, they pull me back in.”)

I thought I was essentially done in early June, after I turned in the last chapter. Then the reviews came back, and most of them were really positive, so I was very hopeful I was actually finished.

That’s when the tech editor chimed in.

In addition to the regular reviewers, Manning hires a tech editor for each book. I didn’t realize what that meant until I saw the result. My tech editor, Valentin, ripped my poor baby apart.

Except he didn’t, really. He just identified all the flaws I knew about and many that I’d missed. He did a fantastic job, actually, darn him.

After recoiling in horror, I eventually developed the following pattern. For each chapter, I would

  1. Read all the comments, trying not to (over)react to them with anger, denial, frustration, or any other emotion
  2. Close the document
  3. Come back at least half a day later, or sometimes a whole day
  4. Read what he actually wrote and start making the changes necessary to improve the book

I would estimate that based on Valentin’s (and the other reviewers’) comments I probably rewrote as much as a quarter of the book during June. In general, I hate rewriting, but the improvements were so obvious I couldn’t even complain about the process, though I tried. I just wish I could have shortened it a bit, but so be it.
The book is much, much better now. I hope you like it too.

After that I finished the rest of the book, meaning the preface*, acknowledgements, part headings, dedication page, adding another appendix**, and uploading all the figures. I finished all that last weekend, so I was finally all done.

* Nobody, and I mean nobody, will write a preface like mine. You’ll understand when you read it. I’m sure no one else would ever add 16 footnotes to a 4 1/2 page preface, with comments ranging from Star Trek to Joseph Campbell to the new cover sheets for T.P.S. reports.***

** Installing Groovy, which is so much easier thanks to GVM.

*** We’re putting new cover sheets on all the T.P.S. reports before they go out now. Did you get the memo?

Except I’m not done, because the graphics people want a different format for many of my figures. Plus, my editor (who spent the last ten days in an igloo in Alaska, or some such nonsense) hasn’t signed off on it yet.

So I’m not really done, but I’m awfully, awfully close. I’m still hoping that the book will be available in print in time for JavaOne in September, where I’m giving a talk entitled, “Making Java Groovy”. Yes, that’s the same name as the book, by an astonishing coincidence. I’m part of a large Groovy contingent at JavaOne this year, which is really groo^H^H^H^H cool.

One side effect of finishing will hopefully be the resurrection of my blog. I stopped blogging when I discovered that there were only so many words I could write in a day, and they really needed to go to the book rather than here. Now that that’s done (hopefully), I can start bringing my blog back to life.

For example, I did far less metaprogramming in the book than I wanted to, but I did come up with a simple example of a category in Groovy, which I implemented both in the old way and the new way.

Here’s the old way, saved in a class called CurrencyCategory.groovy:

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)
    }
}

Note that both methods are static, and that their first argument is java.text.NumberFormat. That means the methods are added to the NumberFormat class.

The new way (as of Groovy 2.0, so not all that new, really) is in a class called AnnotationCurrencyCategory.groovy:

import java.text.NumberFormat

@Category(Number)
class AnnotationCurrencyCategory {
    String asCurrency() {
        NumberFormat.currencyInstance.format(this)
    }

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

This class uses the @Category annotation, and the included methods are now instance methods that are added to class that is the argument of the annotation.

Here’s a test case to make sure they’re working:

public class CurrencyCategoryTest {
    public static final String EURO = '\u20ac'
    def amount = 1234567.89012

    @Test
    void testCurrencyCategory() {
        use(CurrencyCategory) {
            if (Locale.default == Locale.US) {
                assert amount.asCurrency() == '$1,234,567.89'
            }
            assert amount.asCurrency(Locale.GERMANY) == "1.234.567,89 $EURO"
            assert amount.asCurrency(new Locale('hin','IN')) == 'INR 1,234,567.89'
        }
    }

    @Test
    void testAnnotatedCurrencyCategory() {
        Number.mixin AnnotationCurrencyCategory
        if (Locale.default == Locale.US) {
            assert amount.asCurrency() == '$1,234,567.89'
        }
        assert amount.asCurrency(Locale.GERMANY) == "1.234.567,89 $EURO"
        assert amount.asCurrency(new Locale('hin','IN')) == 'INR 1,234,567.89'
    }
}

In the first test, I employ a use block. Inside the use block, the category methods are added to the NumberFormat class. In the second test, I use the mixin method to make the new methods available.

Pretty cool, eh? I have a lot more examples to present, but that’s enough for a single blog post. More to come, on a much more regular basis now.

I’ll let you know when I’m really, really done, at which point I start rolling out the Silly Marketing Ideas (abbreviated SMI, as opposed to the Serious Marketing Ideas, abbreviated SMI). You’ve been warned.

%d bloggers like this: