Skip to main content

JavaBeans, Binding, and AOP

Posted by javaben on June 1, 2006 at 9:19 AM PDT

My friend Richard Bair recently told the world that the colloquial definition of JavaBeans as an object with getters and setters is incomplete, and demonstrated how a handy base class can make adding PropertyChangeListener support easier.

I'd like to pick up where his discussion left off. Over the past few years, I've been pondering how to make it easier to develop Swing applications. One area of pain in Swing is binding; that is, copying values from Swing widgets to business objects and vice-versa.

Swing components, as Richard mentioned, are observable via PropertyChangeListeners and other types of listeners, so detecting when widget values are changed and copying those values to objects as a result is pretty easy (though there are a few subtleties to get right). The reverse, however, is not free. In order to detect when values in an object have changed, one needs to use some mechanism like the JavaBean spec to introduce observability into JavaBeans.

And for me, therein lies the rub. Firstly, I hate repeating myself, and writing firePropertyChange("property", old, new) over and over again seems a big pain. Second, the string literal gives me the heeby-jeebies. If I'm going to all the bother of using a strongly-typed language, I hate having the bugs of loose-typing introduced with none of the benefit. Third, what if I'm using some pre-constructed business objects that aren't observable and can't easily be made to be observable?

(A quick tangent: Everyone ought to know that walking stacktraces is one of the most expensive VM operations around. Yet, just for fun, I created a version of firePropertyChange(...) that automatically obtains the property name by walking the stacktrace. Here it is:

    protected void firePropertyChange(Object oldValue, Object newValue) {
        try {
            throw new Exception("stacktrace");
        } catch (Exception e) {
            StackTraceElement[] st = e.getStackTrace();
            String property = ReflectionUtils.getPropertyFromAccessor(st[1].getMethodName());
            firePropertyChange(property, oldValue, newValue);

Never use this code in a tight loop.)

For all these reasons, the binding solution I use takes a hybrid approach. To save myself a lot of explanation, let me just say that when the Swing widget's value is changed, the framework can copy the value to the business object automatically, but the framework does not copy the value back to the Swing widget until the developer specifically requests that the value be copied from the business object back to the Swing widget.

In practice, it looks something like this:

    binder.defineBinding(businessObject, swingWidget, "fieldName");
    // at some future point, call this next line to update the UI from the object

I've used variations on this technique for a while now, and it works very well. When combined with a container-managed form system, it actually works nearly as well as true bi-directional binding as the form lifecycle can introduce automatic calls to binder.updateWidgets() at various flow points (and the automatic behavior can of course be disabled).

But I've been aware for a long time what the real solution to this problem is: Aspect-Oriented Programming (AOP). Using AOP, you can easily add PropertyChangeListener support to any object, even those for which you don't have source code, and generally solve all three of the problems I have with manually adding PropertyChangeListener support.

Unfortunately, I don't use an IDE that has AOP support, so I haven't been able to explore AOP much up to now. But the latest release of my favorite AOP framework, AspectJ 5, enables a new type of AOP syntax based on Java 5 annotations (called @AspectJ).

Using @AspectJ, I can create a simple class that handles all of this property firing for me:

    public class JavaBeanObservabilityAspect {
        @Around("execution(* *.set*(..))")
        public void timeElapsed(ProceedingJoinPoint jp) throws Throwable {
            if (jp.getTarget() instanceof JavaBean) {   // only fire listener if a JavaBean
                JavaBean o = (JavaBean) jp.getTarget();
                String property = ReflectionUtils.getPropertyFromAccessor(jp.getSignature().getName());
                Object oldValue = ReflectionUtils.invokeAccessor(o, property));
                // proceed with the invocation of the method
                Object newValue = jp.getArgs()[0];
                o.firePropertyChange(property, oldValue, newValue);
            } else {
                // if not a bean, just proceed with the invocation normally

The above is a crude beginners example of how to automatically fire the event on all JavaBeans -- a more refined example would show you how to actually add PropertyChangeListener support dynamically to any object. The example I gave is also problematic in that if the setter already fired the event, it would be fired again by the aspect. And, I coded this version here in my blog, so if it doesn't compile, don't sue me. But... you get the idea.

The beauty of @AspectJ is that because it just uses normal Java 5 annotations, you can use your IDE to create and compile the aspects like any other part of your code base. To actually use the aspects at run-time, you must weave the aspect into your code.

Weaving is the process of augmenting Java classes with the additional instructions defined by one or more aspects (such as the one above). You do that with a special compiler that comes with Ant tasks that can be easily introduced into your build process.

But for the impatient, there's this cool new thing in ApsectJ 5 called load-time weaving ("LTW"). With LTW, you pass your JVMTI compliant (Java 1.4+) VM a property that configures an agent that can weave your classes as they are loaded:


You then create an XML file (META-INF/aop.xml) that specifies with aspects to weave, and into which classes, such as:

            <aspect name="org.galbraiths.beans.JavaBeanObservabilityAspect"/>
        <weaver options="-verbose -showWeaveInfo">
            <include within="org.galbraiths.beans.JavaBean"/>

And presto! You've got AOP in your project (along with a handy speed hit whenever the affected classes are loaded for the first time). There are all kinds of fun things to do with AOP, such as introducing ultra-low-intrusion microprofiling, verifying proper Swing threading, and so forth. Blogs for other days.

So -- for the purposes of binding, you may not need observability in your objects, but if you do want it, consider AOP for adding observability without repeating yourself all over your codebase -- and for adding it to code you don't control.

If the pretty good AspectJ project documentation doesn't do it for you, check out AspectJ in Action, written by Ramnivas Laddad -- a friend and collegue whom I greatly respect. His book doesn't cover @AspectJ, but is widely considered the best AspectJ book around.

As with most of my entries, this was cross-posted on my personal blog, Married... with Children

Related Topics >>