Building Rich Swing Applications with Groovy - Part III - No Fluff Just Stuff

Building Rich Swing Applications with Groovy - Part III

Posted by: Andres Almiray on December 3, 2009

The following article appeared on Groovymag's third issue (January 2009). It is the third of a four-part series on Groovy and Swing applications. Be sure to check out Groovymag for more information on Groovy, Grails, Griffon and other GR8 technologies (Gant, Gradle, Gmaven, Spock, etc... :-D)

Building Rich Swing Applications with Groovy - Part III

By Andres Almiray

 

On the third installment of this series we will see how SwingBuilder simplifies binding between visual components and model classes, with a touch of Groovy magic.

 

We have covered a lot of ground on the previous two articles, from the beginnings of Swing through Groovy's answer to some of its painful points, up to extending SwingBuilder's capabilities and a glance at some of the official extensions in the form of SwingXBuilder and JideBuilder. But desktop applications shouldn't just look good, they should behave nicely and provide a great user experience,  in order to do that your visual components should communicate with your domain or business logic in a streamlined way, this is when binding comes into the scene and usually when things start to go awry.

Binding in a Nutshell

While POJOs are now recognized as a viable way of defining your domain they lack the default powers to serve effortlessly as a communication packet between the members of the MVC pattern, you are required to enhance them with a standard contract, one of an observable bean (note: there is no special interface that needs to be implemented to let a bean become observable). To make a bean observable with regular Java means it is recommended that you compose a PropertyChangeSupport helper on your bean class, provide listener registration methods (as shown in the following listing) and fire PropertyChangeEvents whenever a property's value has been successfully updated.

 

Listing 1


 

Java, by virtue of its preference for static typing, will force you to write every single property accessor method,  the observable bean convention suggests you should fire change events on the setter method. Groovy, by virtue of being hip and dynamic, will write those property accessors for you automatically, but that poses a problem with event firing, as you would be required to write property setters by hand in order to fire events, if only there was a way to mark those beans or properties as observable and let Groovy handle the plumbing, oh wait, there is!

Making Beans Observable the Easy Way

Making their debut in the Groovy 1.6 branch (current stable release is 1.6-beta-2 (see update1)) ASTTransformations provide a framework for extending a class behavior at compile time, think of them as compile time meta-programming. In a nutshell what they do is modify a class' bytecode while the Groovy compiler process it (don't worry, it is safe as they must follow the Groovy rules and the compiler will not let them write invalid bytecode).  ASTTransformations need a clue to know where to work their magic, that clue is given by specially crafted annotations, in our case that job falls into the @Bindable annotation.

 

@Bindable is a two-headed beast (a very friendly one mind you), when used at the class level it will instruct the ASTTransformations to add a PropertyChangeSupport field to the class if none is found, it will also add the required observable contract for listener registration, lastly it will generate property accessors with event firing code already wired up for every property in the class. Alternatively when used at the property level it will follow steps 1 and 2 (if needed) but will only mark that particular property as observable, in other words, its property mutator (the setter) will have event firing code. Here is a very basic example of its usage

 

Listing 2


 

Once you start using @Bindable you will feel that a void has been filled up, it surely should have been there from the beginning! For those of you that can't jump into Groovy 1.6 right now, don't worry, there is an alternative: ObservableMap.

Observable Not-a-Bean Bean

Quick quiz: in Groovy, when is a a bean (or something that looks and behaves like one)  not a bean? when it is a Map. Groovy has blurred the line between beans and Maps, so it should also be natural that observables beans could be replaced by their observable Map counterpart. That is what ObservableMap does, plus a little more. Properties on beans are static, even in Groovy (wait isn't Groovy dynamic? let me explain) because you cannot add/remove then at runtime and be notified of such events, not unless you decide to add that behavior via ASTTransformations or some other means but we're getting off the subject. Maps on the other hand support addition/removal of properties, wouldn't it make sense to trigger events when that happens as well, not just on property value updates? the good news is that ObservableMap does that too, it even leverages PropertyChangeListener / PropertyChangeEvent as base classes for event handling/firing, meaning that your regular bean event handlers will work with this type of Map, the following figure shows an example of the type of events fired by an ObservableMap when properties are added, updated, removed and eventually cleared from the map.

 


Figure 1 An ObservableMap example

 

Another line that Groovy has blurred is the distinction between arrays and Lists. While there is no way to make an array observable, there is however the possibility of observable Lists, wouldn't it be swell to have them too? well what do you know, Groovy provides an ObservableList class too, and what a surprise it follows the same principles of ObservableMap, like reuse of  PropertyChangeListener / PropertyChangeEvent, custom events for add/update/remove/clear, as demonstrated by the next figure

 



Figure 2 An ObservableList example

 

Alright so we have various alternatives for observable sources and targets, how do we make them talk to each other?

Binding with SwingBuilder

Binding in SwingBuilder is done pretty much in the same way as building any other component, you just insert a bind node in specific locations. Before we get into specifics you should now that SwingBuilder's binding was inspired by JSR 295 (BeansBinding) at least in spirit, as it does not use any of the classes of the available reference implementation [side note: it has been recently announced at Devoxx 08 by the powers that be that BeansBinding will not be included in the next version of Java (JDK7)]. Let's start with a trivial example and see where it leads us, say you would like to update the value of a textField with the value of another textField as the user types it, this rather contrived application may look like the following figure

 


Figure 3 Simple binding application

This is the code used to produce such application

 

Listing 3


 

TextField t1 is the source, TextField t2 will be the target. There is no need for t2 to be non-editable for binding to work, its only purpose is to show that it's value can only be changed if you type something into t1. Seasoned Swing developers may have spotted a common gotcha on JTextField, its text property is not observable! it actually fires another type of event when its value is updated, what makes SwingBuilder's binding great is that it translates one event into the other for you and calls the expected listeners, hiding that complexity (but not hindering the actual pipework).

 

While this first approach is fine and dandy the agile developer is screaming "DRY! DRY!" (Don't Repeat Yourself in agile speak) and I would agree with him, there should be a way to add this binding without needing to repeat the references to both textFields. Fortunately there is one, use the bind node as the value of the property you would like to update, like the following code shows

 

Listing 4


 

When used on this mode the bind node will assume that the current node is the target and that the current property will be the targetProperty. Knowing this fact you can also arrange the code to work  the other way around, having t2 update t1 with the bind node applied to t2

 

Listing 5


 

But we are still getting a small amount of visual clutter, it is clear to us that t1 is an observable bean and that we desire to bind its text property to another bean, can SwingBuilder figure that out too with less keystrokes? following the trend of questions asked on this series you surely know by now the answer is happily yes! SwingBuilder (in the 1.6 branch) sports a short binding syntax inspired by JavaFX Script's binding syntax. In case you do not know what JavaFX Script is, it is a language designed for creating Java UIs in a declarative way (wait, isn't that what Groovy and SwingBuilder already provide? but that is a different discussion, back to our article), that borrows features from a handful of languages like Ruby and JavaScript. One of its key features is binding, and a good one that is, as you can pretty much bind to any expression. Back to Groovy we can't bind to any expression as not all statements in Groovy are expressions, and even it they were it would probably require grammar changes. But we can bind to closures, after all they behave like short and scoped expressions, which is exactly what the short syntax requires. Here is a rewrite of Listing 4 using the short binding syntax

 

Listing 6


 

Talking about being expressive, the short binding syntax plus the bind node at the correct place really helps in reducing the amount of code required for visual components and domain classes to communicate via events. If you think this is all there is to binding you'll be surprised, there is still a bit more.

Additional Binding Properties

Binding has a handy sidekick which likes to play the role of a policeman, yes I'm referring to validation. Often times in enterprise applications data must be validated both syntactically and semantically. While semantic validation is preferably left to the business layer of the application, syntactic validation is usually performed by both view and controller. The bind node can help the view in that regard by allowing a closure to be use as a trigger filter, if the filter returns null or Boolean.FALSE then the trigger will be canceled and no event will be fired. Let's try it out with an updated version of the simple binding application, this time we will only allow an integer value to be written to textField t2

 

Listing 7


 

Unfortunately the validator property cannot be used in conjunction with the short syntax at the moment, that may change in a future release. If you run this example you will notice that t2 will be updated when t1 contains only numerals and no other type of characters.

 

Another useful binding option is translating the source value into a different one, this task is easily accomplished by providing another closure as the value of a converter property on the bind node. Let's rewrite the application once more, this time the value of t2 will be updated with the character '#', as many characters typed on t1's value

 

Listing 8


 

If you try to set a converter value along with the short syntax you will quickly notice that it doesn't work as expected, that is because when the short syntax is used the converter should be merged with the bound closure, in other words the previous example would become

 

Listing 9


 

Finally there may be times when you wish an event was automatically translated into another one but it is not, the bind node also offers a way to achieve this goal, just define appropriate values for two other properties: sourceEvent and sourceValue. SourceEvent should be a string that identifies the action handler that fires the desired event, sourceValue should be whatever value you want that will be used as the event's value. The following listing shows another application where a button is used as the event trigger, its actionPerformed event handler is used as the source, a counter is used as the event's value, its accompanying figure clearly reveals what is being written to the textField one the button has been clicked 5 times.

 

Listing 10




Figure 4  The button has been clicked 5 times

A Word of Caution

While all the binding examples shown in this article will work with Groovy 1.6 (the short syntax will not work in Groovy 1.5.7) there is currently no support for two-way binding, a very desirable flavor of binding. This situation however may change in a future release but there is not official word yet (see update2).

What's Next?

SwingBuilder provides you with declarative UI programming, extension hooks, binding and a couple features more yet to be discovered, all that is great but it falls short when it comes to putting all the pieces together to create a solid application, it's not its fault after all it wasn't designed for such a task. What we need is an application framework, something that leverages SwingBuilder's strong features and your Java knowledge, something that allows you to reuse any Swing library / component / extension that is out there in the wild, something that enables higher productivity,  perhaps even follow the convention-over-configuration paradigm that has been all the rage in web application development during the latest years, we need a framework that harnesses Groovy as a glue language. Yes, I'm saying we need something like Grails but for Swing development, that is the ambitious goal of Griffon, be the Grails of desktop application development.

Conclusion

We have discussed several options SwingBuilder puts at your fingertips to let visual components and domain object communicate via binding, we have also seen a glimpse of compile time meta-programming with ASTTransformations, a  new feature in Groovy 1.6 that lets you update the generated bytecode of classes marked with special annotations, like @Bindable. Lastly the need of a Swing application development that ties everything together in a nice package has been voiced and answered by Griffon, which will be the main topic of this series.



Update #1:The latest stable release on the 1.6 branch is 1.6.6. The latest development release is 1.7-rc1. Both were recently released a few days ago.
Update #2:Actually it is now possible to have bidirectional binding, just be sure to declare a mutual: true property on your binding, like this


Keep on Groovying!
Andres Almiray

About Andres Almiray

Andres is a Java/Groovy developer and a Java Champion with more than 20 years of experience in software design and development. He has been involved in web and desktop application development since the early days of Java. Andres is a true believer in open source and has participated on popular projects like Groovy, Griffon, and DbUnit, as well as starting his own projects (Json-lib, EZMorph, GraphicsBuilder, JideBuilder). Founding member of the Griffon framework and Hackergarten community event. https://ch.linkedin.com/in/aalmiray

Why Attend the NFJS Tour?

  • » Cutting-Edge Technologies
  • » Agile Practices
  • » Peer Exchange

Current Topics:

  • Languages on the JVM: Scala, Groovy, Clojure
  • Enterprise Java
  • Core Java, Java 8
  • Agility
  • Testing: Geb, Spock, Easyb
  • REST
  • NoSQL: MongoDB, Cassandra
  • Hadoop
  • Spring 4
  • Cloud
  • Automation Tools: Gradle, Git, Jenkins, Sonar
  • HTML5, CSS3, AngularJS, jQuery, Usability
  • Mobile Apps - iPhone and Android
  • More...
Learn More »