Skip to main content

BeansBinding: not only for the GUI?

Posted by fabriziogiudici on January 13, 2008 at 8:02 AM PST

"Beans binding" is, in general, any Java technology that allows to automatically bind some properties in a plain JavaBean class to a GUI form. There have been libraries around for beans binding since a few years, but the thing is getting more and more interest  because of JSR-295, an official specificaion from Sun together with its reference implementation ("Beans Binding in capitals) that is also supported by NetBeans 6.

Don't worry: this is not Yet Another Tutorial on NetBeans and BeansBindings since there are already around (even though it seems there's nothing about the use of JSR-295 with NetBeans RCP projects). My point is about using Beans Binding for other purposes than merely bind a form - you know that I like to use stuff also for different things than the ones it has been designed for.

Just be warned that this is only work in progress at the time.

The context: blueMarine Metadata

Let me start with the context, which is a new sub-project of blueMarine which is called blueMarine Metadata and, as it appears obvious from its name, it has the responsibility for managing metadata of photos. In a few words, the requirements are:

  1. The system must be able to manage different items of metadata (for instance, two common kinds for photos are EXIF and IPTC, but we should also consider geotags and other stuff that could come up in future) and the code for managing a new metadata item must be pluggable.
  2. The system must be able to manage different sources of metadata. For instance, an obvious metadata source is the image file itself (e.g. a JPEG or a TIFF), but there is also XMP (a "sidecar" format invented by Adobe, that is an extra file just placed side by side to the original photo file) and there could be a persistent database for performing fast queries.
  3. The persistent technology must be pluggable - JPA being the most common one, but it should not be exclusive; also the underlying database should not be constrained to be a RDBMS.
  4. Components must be reusable as there are different targets for them, blueMarine being only the primary one, and web applications another possibility.

I'm particularly sensible about reusability as this metadata stuff will evolve in some interesting stuff in the next months, but I'm not going to tell you more about it now (yes, this is a little teaser ;-). At the moment I would just like to point out that the NetBeans integrated support for Beans Binding is great for writing GUI forms quickly.

Common design patterns

Since this module is being developed mostly by TDD and I have a very good test coverage, I can afford to do some experimenting, especially in the area of persistence.

Let's first look at this diagram:

The upper part of the diagram shows a very common pattern that people use, probably influenced by some J2EE blueprints:

  1. the GUI calls the Business components
  2. the Business components call the Persistence components

The left-to-right arrows not only reflect the flow of the incoming requests, but also the dependencies of components:

  1. GUI components depend on Business components
  2. Business components depend on Persistence components

This approach is clearly influenced by J2EE blueprints - in fact, many parts of blueMarine are designed on it, clearly reflecting the fact that when I started the project I was at 99% a J2EE architect. There are two major drawbacks here:

  1. While the approach is well suited to Web 1.0, where every transaction is initiated by the client (information is "pulled"), there is no support for changes that might initiate, for any reason, from the business tier. This can be managed by a full fledged MVC pattern, and in fact rich desktop applications have been using it for decades (and Web 2.0 started too). To avoid introducing a dependency from the Business tier to the GUI, MVC uses the Observable pattern: the Business object exposes a "listener" API, that the GUI uses to register and receive notification of changes.
  2. The Business objects depend on the Persistence technology, which is not good since it forces you to use a specific technology. Usually people solve this by introducing factories and interfaces for decoupling, which works but introduces complexity. A better solution here is to apply Inversion Of Control and have Persistence depend on Business. At this point the interaction between the Business and the Persistence can be implemented with a specular kind-of-MVC by means of listeners, so Persistence receives change notifications from Business.
    I've not drawn the capability of Persistence to be the originator of changes and call Business to modify it since if we're thinking of a database this usually doesn't occur; but in my case, where Persistence could be an image file, this might happen if somebody changes it on the disk with another editing tool. So replicating the MVC has a further benefit.

Beans Binding for Persistence

And now my point. Beans Binding is basically used as an alternate approach to implement MVC for the GUI and the Business objects without requiring you to write specific listeners; instead, Beans Binding takes advantage of the standard java.beans.PropertyChangeListener implemented in the Java runtime, posing as an additional requirement that all the involved objects are compliant with the JavaBeans specification (remember that a "real" JavaBean is not the same as a POJO, as it must have proper event notification upon every property change). This is an annoyance that I'll address at the end of this post, but I anticipate that it's just a boilerplate code issue, not a design problem.

But if the relationship between Business and Persistence can be expressed as a kind-of-MVC, why don't we use Beans Binding to take care of the relationship between Business and Persistence too?

It's basically what I've done so far in the first sketch of the blueMarine Metadata subproject, as explained by the upper part of this diagram:

Now Form, Domain Object and Persistence are pretty much decoupled each from the other - it's up to two special services, the UI Binder and the Persistence Binder, to use JSR 295 for keeping them synchronized. Any change in any object will properly reflect into the others: this happens both if the user types something in the form (and the update is propagated to the Business and Persistence objects) and if something changes in Persistence (and the update is propagated to the Business and the Form); of course changes could also originate in the Business Object (e.g. a timer triggers) and the other two are updated.

Keep in mind that the Business Object mustn't be a passive thing such as a Value Object, but it can contain business logic too (i.e. a property change might originate some computing); on the other hand, the "Binders" are Services that need to be invoked only once, to set up bindings, and then they don't have a further role in the evolution of the object states. I like this approach since it seems to overcome the classic scheme of "active-Services" versus "passive-Objects", instead here each object is active and its design is only driven by the domain model.

Also, in the example the Persistence object seems to be modeled on the Domain Bean (same properties), but this is not a constraint. For instance, in blueMarine I have implemented a persistent module where every property from every JavaBean is storead as the tuple ("metadata group", "metadata property name", "value") in a single table. Beans Binding gives you a lot of flexibility.

Two problems

There are two problems in this design, both related to the specific technology available now:

  1. Transactions. What should demarcate them? Thinking of a user that is typing in the Form, and wants changes to be persisted, we should have something as: the user types, but Beans Binding doesn't propagate changes immediately; instead, when the user presses a "Save" button we have the sequence "press Save -> begin TX -> propagate changes -> commit TX". Another approach (which is the one I want for blueMarine) could be that each change is automatically committed to the database while the user types in the form (the sequence is "type -> begin TX -> propagate changes -> commit TX"). Unfortunately, the current support for JSR 295 by NetBeans Matisse for NetBeans RCP projects doesn't allow you to do any customized transaction demarcation (the problem is addressed only when JSR 295 is used in conjunction with the "Swing Application Framework", JSR 296) - indeed, with NetBeans RCP there will be no transaction at all in the generated code.
  2. The infamous AWT Thread. Changes that originate from the Business Object or the Persistence are not executed in the AWT Thread, but any change to the Form must be performed from within it; unfortunately JSR 295 at the moment doesn't support this automatically.

My solution is to add two decorators:

  1. The Transactional Decorator ensures that every property change (incoming from the left side of the diagram) is wrapped by a begin TX/commit TX (of course we might think of putting this decorator at the left of the Business Object if we want transactions to have an effect on it, but this is just a minor detail).
  2. The AWT Thread Decorator ensures that every property change (incoming from the right side of the diagram) is performed by a SwingUtilities.invokeLater().

But of course we don't want to code these decorators by hand. We could use java.lang.reflect.Proxy to generate a dynamic proxy, but unfortunately it requires an interface and Java Beans don't have any (rant: why the JavaBeans specification doesn't take care of interfaces?). A solution can be provided by the CGLIB library, which allows to create a dynamic proxy starting from a concrete class, by means of bytecode manipulation:

package it.tidalwave.metadata.persistence.jpa;

import java.lang.reflect.Method;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class TransactionalBeanFactory
    public EntityManager entityManager;
    public <T> T createTransactionalDecorator (final T object)
        final Enhancer e = new Enhancer();
        e.setCallback(new MethodInterceptor()
            public Object intercept (final Object obj,
                                     final Method method,
                                     final Object[] args,
                                     final MethodProxy proxy)
              throws Throwable
                boolean demarcateTransaction = ...;

                if (demarcateTransaction)
                final Object result = proxy.invokeSuper(obj, args);

                if (demarcateTransaction)
                return result;
        return (T)e.create();

A similar approach could be used for the AWT Thread Decorator.

If you're thinking of AOP, yes, we are basically implementing an aspect here. But I prefer to do it manually with CGLIB rather than resorting to AspectJ for simplicity, as I don't want to add another complex library (and a new language) to my project.

What about boilerplate code?

It's known that properly implementing JavaBeans with all the listener stuff is a PITA. While for the UI stuff you could just extend the AbstractBean class from SwingLabs, and 90% of the work is done, this is not a viable solution for the Business and the Persistence objects for two reasons:

  1. It's bad to use a Swing specific library in these tiers;
  2. I don't like solutions requiring inheritance.

At the moment I've resorted to some quick and dirty tool for automatically generating the required boilerplate code, but I think I'll try the CGLIB approach again, by generating a decorator that turns a simple POJO into a full-fledged JavaBean. Before doing this I'll carefully search if there's already something implemented for this.

The current state of this stuff is that tests pass, but the thing doesn't work in production yet, since CGLIB has some conflicts with the NetBeans RCP classloader. This is something that I hope to fix soon. There are other specific desing issues that I'm dealing with, most notably another module of blueMarine where I'm trying to apply this scheme but it falls short of a specific case. But this is just preliminary work, expect updates from me in future.

In the meantime, I'd like to have some feedback from you.

PS If this works, I wonder wheter the JSR-295 package name org.jdesktop.beansbinding is somewhat inappropriate, since the scope of the technology goes beyond the desktop. Perhaps org.beans.beansbinding would be better?

Technorati Tags: , ,


Nice utility Steve, thanks.
I took the liberty to enhance it a bit. First, I added support for "write-only" properties, then I changed the order so that the setter is called on the bean before the property change event is fired, and finally, I added support for "setter chaining", so you can have beans like this:

class Bean { public Bean setOne(int newValue) { one = newValue; return this; } public Bean setTwo(int newValue) { two = newValue; return this; } private int one; private int two; } Bean b = new Bean(); b.setOne(1).setTwo(2);

Here's the PropertyChangeMethodInterceptor with my changes:

import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; final class PropertyChangeMethodInterceptor implements MethodInterceptor, PropertyChangeListenerSupport { // // Life-cycle: // PropertyChangeMethodInterceptor(Object bean) { this.bean = bean; propertyChangeSupport = new java.beans.PropertyChangeSupport(bean); } // // MethodIntercepror API: // public Object intercept(Object object, Method method, Object[] methodParameters, MethodProxy proxy) throws Throwable { // If property change listener method is called, pass it to 'this': if (propertyChangeListenerSupportMethods.contains(method)) { return method.invoke(this, methodParameters); } // If method other than setter is called, pass it to bean: if (!method.getName().startsWith(SET_PREFIX)) { // No, pass the call to bean. return method.invoke(bean, methodParameters); } // // Setter called. // // Try to get the old value, call the setter, and finally fire a property change event: // // Get the property name: StringBuilder methodSuffix = new StringBuilder(method.getName().substring(SET_PREFIX.length())); // Get the old value, or use null if bean does'nt have a getter. Method getMethod = getGetter(object.getClass(), methodSuffix); Object oldValue = (getMethod != null) ? getMethod.invoke(object) : null; // Call the setter: Object returnValue = method.invoke(bean, methodParameters); // If the setter returns the bean itself, return the wrapped object instead. This // provides support for "setter chaining". if (returnValue == bean) returnValue = object; // Change the first letter to lower case and fire property change: methodSuffix.setCharAt(0, Character.toLowerCase(methodSuffix.charAt(0))); propertyChangeSupport.firePropertyChange(methodSuffix.toString(), oldValue, methodParameters[0]); // Return what ever the setter returned: return returnValue; } // // java.beans.PropertyChangeListenerSupport API: // public void addPropertyChangeListener(java.beans.PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } public void addPropertyChangeListener(String propertyName, java.beans.PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(propertyName, listener); } public void removePropertyChangeListener(java.beans.PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } public void removePropertyChangeListener(String propertyName, java.beans.PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(propertyName, listener); } // // Private stuff: // /** * Get the getter for given property, or <code>null</code> if bean does not support * getter for given property. * * @param beanClass <code>Class</code> of the bean * @param propertyName Property name * @return Getter method, or <code>null</code> if getter is not supported. */ private Method getGetter(Class<?> beanClass, StringBuilder propertyName) { // Try the 'get' getter first: try { return beanClass.getMethod(new StringBuilder().append(GET_PREFIX).append(propertyName).toString()); } catch (NoSuchMethodException e) { // No 'get' getter, proceed... } // Try 'is' getter: try { return beanClass.getMethod(new StringBuilder().append(IS_PREFIX).append(propertyName).toString()); } catch (NoSuchMethodException e1) { // No 'is' getter either, proceed... } // Return null indicating that this bean does not have a getter for this property. return null; } private final java.beans.PropertyChangeSupport propertyChangeSupport; private final Object bean; private static final List<Method> propertyChangeListenerSupportMethods = Arrays.asList(PropertyChangeListenerSupport.class.getMethods()); private static final String SET_PREFIX = "set"; private static final String GET_PREFIX = "get"; private static final String IS_PREFIX = "is"; } -jarppe

Thank you for the contribution, it will save me some time :-) BTW, I've fixed my NetBeans problems with CGLIB and clarified some parts of my idea, as soon as I can find the time for blogging I'll post a follow-up.

Fabrizio, Excellent article. We did the a similar thing for PropertyChangeSupport as follows: public class BeanProxyFactory { public static T createPropertyChangeProxy(T bean) { return (T) Enhancer.create(bean.getClass(), new Class[] {PropertyChangeListenerSupport.class}, new PropertyChangeMethodInterceptor(bean)); } } public interface PropertyChangeListenerSupport { void addPropertyChangeListener(String propertyName, PropertyChangeListener listener); void addPropertyChangeListener(PropertyChangeListener listener); void removePropertyChangeListener(String propertyName, PropertyChangeListener listener); void removePropertyChangeListener(PropertyChangeListener listener); } public class PropertyChangeMethodInterceptor implements MethodInterceptor, PropertyChangeListenerSupport { private static final String SET_PREFIX = "set"; private static final String GET_PREFIX = "get"; private static final String IS_PREFIX = "is"; private PropertyChangeSupport propertyChangeSupport; private Object source; public PropertyChangeMethodInterceptor(Object source) { this.source = source; propertyChangeSupport = new PropertyChangeSupport(source); } public Object intercept(Object object, Method method, Object[] methodParameters, MethodProxy proxy) throws Throwable { // check for property change methods if (Arrays.asList(PropertyChangeListenerSupport.class.getMethods()).contains(method)) { return method.invoke(this, methodParameters); } // if the call is to a setter, we need to fire a property change if (method.getName().startsWith(SET_PREFIX)) { // determine the name of the property StringBuilder propertyName = new StringBuilder(method.getName().substring(SET_PREFIX.length())); Method getMethod = null; // try to get a method with a "get" prefix. if that doesn't work, try an "is" prefix try { getMethod = object.getClass().getMethod(new StringBuilder().append(GET_PREFIX).append(propertyName.toString()).toString()); } catch (NoSuchMethodException e) { // might be a boolean get method with an "is" prefix getMethod = object.getClass().getMethod(new StringBuilder().append(IS_PREFIX).append(propertyName.toString()).toString()); } // get the old value Object old = getMethod.invoke(object, (Object[]) null); // change first letter to lower case propertyName.replace(0, 1, propertyName.substring(0, 1).toLowerCase()); // fire a property change propertyChangeSupport.firePropertyChange(propertyName.toString(), old, methodParameters[0]); } return method.invoke(source, methodParameters); } public void addPropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(propertyName, listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(propertyName, listener); } } The idea is to pass a class to the factory and get back a class with PropertyChangeSupport built in. A one-liner.

It is clearly a matter of preference and philosophy, but this is for our purposes an attractive alternative to AOP.

The main thing is, this took a lot of the pain out of the beansBinding framework.

As you mentioned, it does require using CGLIB.


Hi interesting post, personnaly I used aspectJ to intercept setter and insturment add/removeProperty change listener. It allows to have configurable point cut matching easily configurable with Spring. For Event Dispatch Thread issues I use Spin

Thank you for pointing to Spin! I'm doing a similar stuff in these days and maybe it can save me time. I'm going to try it.