
Building Rich Swing Applications with Groovy - Part I
By Andres Almiray
Creating a compelling user experience with Java Swing is not an easy task. Java developers have been looking for the Holy Swing Grail since the toolkit's debut. Groovy, a dynamic language for the JVM, provides useful features and abstractions that can get you closer to that goal, without relinquishing your Java knowledge.
A Bit of Swing History
When Java was released back in 1995 it received a lot of attention from developers for several reasons, one of them was the promise to write UI applications effortlessly, even run them in different environments, like standalone applications on your desktop or embedded in a browser page. The Java motto at that time was "compile once, run anywhere"; Java came with a virtual machine and an Abstract Windowing Toolkit (AWT for short) that provided a layer over native widgets or peers as they were know at the time. But the AWT proved to be inadequate to build such applications, thus the Swing toolkit was born and took over. This toolkit came with new features, such as the MVC paradigm widely used in other places and UI design, the ability to create your own components and go beyond the native ones, a Java2D based rendering pipeline, a better event model, and most importantly it followed the JavaBeans conventions for component design.
The developers were delighted and quickly embraced this new toolkit, even companies created component suites. Unfortunately not everything went smoothly. Though Swing is a great improvement over AWT it came with a price which has been the bane of Java desktop applications since then: threading issues. It is so easy to turn on the wrong corner of threading alley in Swing, resulting in unresponsive applications, gray rectangles and repaint issues. Also on the Java2D front things were not as merry as you might think; this API provides the basis for rendering anything on the screen, such as Swing components, though powerful it is still a low level API, quickly discouraging many from using it. Lastly, for some time a considerable amount of developers started to harbor unhappy feelings towards Java due to the amount of code you must write to get things done, simply put Java is too verbose for some tastes.
Let's move forward in time, the JVM is now a healthy ecosystem of multiple languages, each one following its own path, sometimes crossing Java's own. You can find functional languages amongst this crowd, also radical new languages, scientific oriented, concurrent friendly, toy and dynamic too. And it on the dynamic ones that Groovy shines like a beacon, beckoning Java developers to greener pastures. Groovy shares many features with other JVM languages like closures, meta-programming, operator overloading, and DSL capabilities. It also provides unique features as specialized operators, byte code manipulation at compile time and class loading too. But what really makes it appealing for Java developers is its seamless integration with Java. While other JVM languages prefer to stay away from Java, Groovy on the other hand embraces it, resulting in a fun, refreshing experience for Java developers, even grants higher productivity at no loss of previous knowledge of Java libraries and frameworks.
Groovy is mostly known in the enterprise world because of the Grails framework, an agile and rapid web development environment that follows the convention over configuration paradigm. Groovy is uses as a glue language for battle tested Java solutions as Spring, Hibernate, Quartz and Sitemesh to mention some; this is possible thanks to the aforementioned qualities of Groovy. It is no surprise that the language with the cool name eventually made it into the Swing arena, after all web applications came after desktop applications.
1. Reducing Verbosity
Let's see how Groovy can make your life easier as a Swing developer. The first step would be to reduce the verbosity level, which Groovy can do quite nicely by itself, by harnessing the power of builders, one of Groovy's options to create your own DSLs. Builders abstract how hierarchies are created in terms of their internal workings, by using a builder you are not required to know how to set the relationship within parent and children nodes. But before I show you the simplified version let's look at a typical short Swing application in Java, like the ones you can find on a text book:
Listing 1.1
Figure 1. Sample Swing application in Java
The example can be broken down in three stages. The first stage defines and configures the widgets that compose the UI (textField, label and button), the second stage adds behavior to the application (the anonymous ActionListener on the button), the final stage puts all the widgets together and displays the main window. Notice that all the code is wrapped inside an anonymous Runnable, this is because it follows Sun's guidelines for Swing development:
- the UI must be built inside the EDT (Event Dispatch Thread).
- any operation that affects the UI must be run inside the EDT.
Failure to follow these guidelines is what usually make Swing applications behave in unexpected ways and leads to tedious hours of bug hunting. Laying out widgets in the desired way is also a headache for many, which is why tools and visual designers have been created, some of those tools use XML as a means to describe how the UI should be composed, there are even frameworks that are based on this principle. Java developers have a love/hate relationship with XML, as soon as Java's verbosity gets unbearable a developer quickly jumps to XML to let it drive those parts that can be defined in a declarative way, to later realize that XML can often times lead to other kind of bugs and nasty runtime errors. Now let's see the same example but in a groovier light, using Groovy's SwingBuilder:
Listing 1.2
Figure 2. Sample Swing application in Groovy
Notice something different between figures 1 & 2? believe it or not they are different applications, one is pure Java, the other is pure Groovy, and they still look the same. This example has the exact same behavior as the previous one (Listing 1.1) but with less code and less visual clutter. The first thing to notice is that there is no apparent threading code involved, also the structure of the resulting UI is easily discernible by human eyes. If you pay close attention to how the gridLayout is constructed, its rows and cols properties have switched places but it still behaves the same, as a matter of fact it is now clear what 3 and 1 mean (they have a property name associated to each one) whereas in the previous example you have to rely on memory or your IDE to find out what those values mean (and the proper order).
The code shown in listing 1.2 looks a lot like the XML definitions some frameworks use to describe the UI, the advantage is that it is still code, compilable code, which means you can catch errors earlier and even insert any valid Groovy expression anywhere you need it. Imagine how ugly and cumbersome would be to define a grid of 4x4 filled with buttons in XML, either you violate the DRY (do not repeat yourself) rule by coping&pasting each button definition with slight updates to their attributes, or you must use a taglib or some other mean to define a nested iteration with XML.
If this example has the same behavior as the previous one, it would be a safe bet that it also builds the application in three stages, right? well almost, it actually combines stages 1 and 3 together, meaning that widgets are instantiated and their properties assigned at the same time those widgets are added to their parent's hierarchy. This clearly reduces the complexity of managing parent-child relationships and demonstrates how SwingBuilder hides that fact from you.
You may probably be thinking "sure labels and buttons are common place, what about the other Swing stuff, more complex components like tables and trees?", well SwingBuilder can handle them as easy as the others, as a matter of fact you can count on SwingBuilder to follow the strategy of removing the leading J of a Swing class and lowering the case of the next char; thus JTable becomes table, JTree becomes tree, JSlider becomes slider, and so forth. I see another question forming on your mind, what about custom components you say? SwingBuilder can handle them too, by giving you two choices: you can either use two generic nodes (container and widget) or you can register your own node handler. Let's look at the first option, as it is the easiest to get you started.
Listing 1.3
This example assumes CustomPanel is a component that extends JPanel (a container) and that CustomComponent (a regular JComponent) has a property named customProperty, as long as the component sticks to the JavaBeans convention it can be used in conjuction with SwingBuilder without no extra effort. On to the second choice
Listing 1.4
Though it took a couple of lines more besides requiring an instance of SwingBuilder the advantage is quite clear, now the custom components blend seamlessly into the UI definition, as if they were included with SwingBuilder from the start. There is a variation to this approach, one that can handle components that require special handling while instantiating them, for example calling a non default constructor (no-args constructor is required by the JavaBeans specification) or a factory method
Listing 1.5
Although trivial, these examples show how SwingBuilder reduces the verbosity level. The next section will explain how SwingBuilder alleviates the common threading problems found in Swing development.
2. Removing the Threading tangle
I like to call Sun's guidelines for Swing threading The Hidden Threading Rules, because as it currently stands there is no way in the JDK nor in the compiler to enforce them, you have to constantly remind yourself about their existence and be on your toes in order not to break them. As you saw on listing 1.2 there were no apparent threading calls to be found in the code, even though that examples does comply with the hidden threading rules, let's look at it again and probably you can spot the place where the magic happens (spoiler: the key is in the static build() method)
Listing 1.2
That's right, the first shield against infringing the hidden threading rules is that SwingBuilder.build() executes the build closure in the EDT for you under the covers, so that you concentrate on building your application. Given Groovy's syntax this example could also be rewritten as follows
Listing 2.1
We have cleared the first hurdle, Groovy makes creating threads a breeze, as it can cast any closure into a Runnable implementation on the fly, which is exactly the type of parameter that SwingUtilities.invokeLater() expects. SwingBuilder.build() has two brothers: edt() and doLater(); the difference strives that the former will call the closure with SwingUtilities.invokeAndWait() or directly if the current thread is the EDT, the latter will always call the closure with SwingUtilities.invokeLater().
If there is a way to ensure your code is run inside the EDT surely there is also a way to ensure it can be run outside of it, if you recall how the event model in Swing works all events are processed inside the EDT, this means that all event listeners are also called inside the EDT, which can be a problem if we are not cautious. Take for example the following File viewer application:
Listing 2.2
Figure 3. FileViewer displays itself
Pay close attention to the inlined action listener on the Load button, it creates a File object, reads its content and sets them on an editorPane. An alarm should be going off on your head right now, no matter if the user inputs the filename for a short file, the UI will appear unresponsive for a few moments as the application will be performing an IO operation on the EDT, now imagine what might happen if the user picks a long file, yes the dreadful gray rectangle and a very unhappy user on the other side of the screen. The solution to this problem would be to read the contents outside the EDT and then later set the contents on the editorPane; I just gave away what we need by carefully choosing outside and later on the previous sentence.
Listing 2.3
I don't know about you but I call this simplified Swing threading, wouldn't you agree? try listings 2.2 and 2.3 with different files (specially big ones) and you'll notice a difference in performance, the latter example behaving better than the former.
Conclusion
There is more to SwingBuilder that what has been shown here so far, the important thing to remember though is that Groovy's SwingBuilder provides a UI building DSL that is easy to grasp, UIs can be constructed easily without needing a visual designer tool. You can also embed any Groovy expression to shape and bend the UI as needed. We also have seen a glimpse of SwingBuilder's extension points, which will be the main topic of the next installment.
UPDATE: a few things have changed since this article was published on November 2008. It is no longer recommended that you use SwingBuilder.build() to create an UI inside the EDT, as it may cause conflict with FactoryBuilderSupport.build(), rather you should create an instance of SwingBuilder and use edt() instead. Here is a revised version of Listing 2.3:
Keep on Groovying!