This summer, a new Java Specification Request (JSR) was defined to provide a simple framework for Swing applications. Although the Java Swing API is around for quite some time now, Java still hasn’t invaded our desktops in the way J2EE has conquered the Enterprise Application domain. By their own admission, the Swing API framework is simply too complex and overwhelming to easily get to grips with it. Due to this fact, Swing just makes it too easy to get it wrong and very hard to get it right when you build GUIs. This JSR intends to fix this problem.
In this article I like to point out a few of the drawbacks of the Swing API that IMHO have held Java back on the desktop. I also like to point out some directions the Java Desktop effort, and in particular this JSR-296, should take to address these issues.
Author: Keesjan van Bunningen (photo), Finalist IT Group, e-mail:
, tel: +31 (088) 217 08 00
Design patterns The Swing API is a showcase for the use of design patterns. But surely this is a good thing?, you might say. Yes, and no. Design patterns are very useful when they help to clarify the overall structure of an API. But it can become a Bad Thing when the patterns are actually overwhelming you and, as a result, hide the underlying structure. It is simply a matter of the forest versus the trees.
And let’s face it, the average Java programmer isn’t really that knowledgeable when it comes to recognizing and applying the concepts of Object-Oriented Programming and Design Patterns. As much as the hardcore Java developer likes to believe that these concepts are an essential and integral part of Java, there is too much Java code out there that provides proof to the contrary. Given this fact, the principles “Less is More” and/or “Keep It Simple, Stupid” (KISS) are far more useful.
So, for instance, dropping the whole concept of listeners to implement event handling is a choice worth considering. Instead of a listener to tie the view to the model, just define a setter for the model on the view and implicitly handle events based on that relationship behind the scenes.
Flexibility The Swing API is very flexible and open to customization. That’s great when you need total freedom to create an imaginative and unique way to present your business data in your GUI application. But it is unnecessarily hard when you just want a run-of-the-mill implementation. Instead, you much rather prefer to focus on the real stuff at hand, namely the data entry/retrieval/processing and the workflow handled within the GUI.
Given this requirement, a far better principle to apply is “Convention over Configuration”, which means that the programmer only needs to define configuration that is unconventional. In other words, the flexibility in the API is there when you need it, but is conveniently hidden when you can’t be bother and just need to get things done quickly.
Low-level constructs The traditional core of Swing, the Swing GUI Components, consists of all the graphical building blocks available/necessary to create a GUI. The buttons, menu bars, pull-down menus, tables, and split panes, to name but a few. Unfortunately, these building blocks are often just too low-level to support rapid GUI development. There’s simply too much boiler plate code required to get even the simplest of GUI components to work. There is a layout to consider, a model / view / controller set to define, and event listeners to be supplied. Again, this is just distracting too much from the real goal that needs to be accomplished.
Multi-threading The most common pitfall of any Java Swing project is the blocking of the Event Dispatching Thread (EDT) by events that are essentially background processes, like for instance data retrieval or data manipulation. This results in the common freeze of the GUI. Of course, a non-responsive GUI is also a Bad Thing and results in a poor user experience. Although this can be avoided fairly easily, it proofs the point that with the Swing API it’s too easy to get things wrong and that it’s hard to get it right.
Preventing this problem from occurring is a far better solution. So hide the threading issues by supplying some kind of Task that kicks off a process in its own thread in the background.
But don’t get me wrong, because the Java Swing API is a wonderful framework that allows you to build the most impressive GUIs. It’s just that it’s complete overkill when you apply it to the mundane GUI applications that are required by customers in our day-to-day job as ordinary Java developer.
IMHO, what’s actually required is an additional layer of abstraction on top of the existing Java Swing API that hides all the tedium and complexity away from view. Instead, it should provide simple solutions to the most common requirements imposed on GUI applications today. These requirements may comprise of the following items, amongst other things: - high-level constructs; - support for the application lifecycle (installation/update, activation, configuration, startup, application state, shutdown, etc.); - data binding and validation; - event handling; - background processing.
Each of these items is a topic on its own and discussing them here will go into too much detail for the purpose of this article. I’ll therefore only highlight a few of them briefly below.
High-level constructs The abstraction layer should consist of elementary, high-level constructs needed to create a GUI application. At the highest level, you will have an Application; the entity that makes up the total desktop application. It should incorporate the basic concepts that every application possesses. It contains all the parts that you come to expect from a GUI application; a title bar, a menu bar, a toolbar, a canvas, a status bar, and the like.
It should be easily configurable to accommodate common needs. For instance, it should support the single-document application or multi-document desktop concept by simply specifying the appropriate configuration. Straight out of the box, no programming required. Likewise for common layout strategies.
Application lifecycle The Application construct should provide the behaviour to support common lifecycle events like startup and shutdown. Other lifecycle events to take into consideration are product activation, installation and/or product updates, and configuration. Persisting application state (for instance, retaining the size and position of the application window after shutdown) is another feature that may be considered.
Data binding and validation The very purpose of any GUI is to present business data and, most often, also allow the user to edit this data. This requires some kind of data binding and validation solution. This solution should impose as little requirements on the data objects themselves, since these (domain) objects often already exist and most likely are not under the control of the GUI developer. An approach based on POJOs and the getter/setter conventions as defined in the Java Bean specifications is a natural choice in this respect.
All the concepts I discussed above are essentially not new. There are a number of existing solutions/frameworks available today (Swing GUI Components, Event Handling, Pluggable Look-and-Feel (PLAF), Internationalization (I8N), Accessibility, Java Beans, Java 2D, etc.) to realize the goals outlined in this article. Therefore, the overall emphasis of JSR-296 should be on re-use and simplification of existing solutions, IMHO.