Previous | Next | Trail Map | JavaBeans Tutorial | Writing Advanced Beans


Implementing Bound Properties


Here is a list of background reading to prepare you for learning bound properties:

The Beans API provides an event mechanism for alerting listeners when Bean properties change. Listeners can be other objects, Beans, components, applications, applets or scripting environments.

There are three parts to a bound property implementation:

There is nothing new here; these are just specific interfaces and classes based on the AWT1.1 event mechanism.

Listeners must implement the PropertyChangeListener interface. Implementing this interface means that

Beans that are the source of property change events must maintain a PropertyChangeListener list, and fire events at each object in that list when a bound property changes. The utility class PropertyChangeSupport implements this functionality. Your Bean can inherit from this class, or use it as an inner class, as you will see.

The PropertyChangeEvent class encapsulates property change information, and is sent from the property change event source to each object in the property change listener list.

Implementing Bound Property Support Within a Source Bean

A Bean containing bound properties must

The java.beans package provides a utility class, named PropertyChangeSupport, which implements two methods that add and remove PropertyChangeListener objects to a listener list, and a method that fires property change events at each listener in that list when a bound property changes. Your Bean can either inherit from PropertyChangeSupport, or use it as an inner class.

To give your source Bean the ability to broadcast property changes events, take the following steps:

  1. Import the java.beans package. This gives you access to the PropertyChangeSupport class.

  2. Instantiate a PropertyChangeSupport object:
       private PropertyChangeSupport changes = new PropertyChangeSupport(this);
       
    This object manages the registered listener list, and property change event notification broadcast.

  3. Implement methods to maintain the property change listener list. Since we instantiated a PropertyChangeSupport object in this example (rather inheriting from it), these methods merely wrap calls to the property-change support object's methods:
        public void addPropertyChangeListener(PropertyChangeListener l) {
            changes.addPropertyChangeListener(l);
           }
        public void removePropertyChangeListener(PropertyChangeListener l) {
            changes.removePropertyChangeListener(l);
           }
      
  4. Modify a property's setter method to fire a property change event when the property is changed. OurButton's setLabel() method looks like this:
        public void setLabel(String newLabel) {
            String oldLabel = label;
            label = newLabel;
            sizeToFit();
            changes.firePropertyChange("label", oldLabel, newLabel);
          }
      

    Note that setLabel() stores the old label value, because both the old and new labels must be passed to firePropertyChange().

      public void firePropertyChange(String propertyName,
                                     Object oldValue, Object newValue)
      

    These values are then bundled into the PropertyChangeEvent object sent to each registered listener. The old and new values are treated as Object values, so if they are primitive types such as int, you must use the object version such as java.lang.Integer. Also note that the property change events are fired after the property has changed.

When the BeanBox recognizes the design patterns for bound properties within your Bean, you will see a propertyChange interface item when you pull down the Edit|Events menu.

Now that you have given your Bean the ability to broadcast events when a bound property has changed, the next step is to create a listener.

Implementing Bound Property Listeners

To listen for property change events, your listener Bean must implement the PropertyChangeListener interface. This interface contains one method:

   public abstract void propertyChange(PropertyChangeEvent evt)
Implementing the PropertyChangeListener interface in your class means implementing propertyChange().

So to make your class able to listen and respond to property change events, you must

  1. Implement the PropertyChangeListener interface.
          public class MyClass implements java.beans.PropertyChangeListener,
                                                       java.io.Serializable { 
          
    This interface contains one method, propertyChange(). This is the method that the property change event source calls when one of its bound propertys changes.

  2. Implement the propertyChange() method in the listener. This method needs to contain the code that handles what you need to do when the listener receives property change event. Very often this is a call to a setter method in the listener class: a property change in the source bean propagates a change to a property in the listener.

To register interest in receiving notification about a Bean property change, call the listener registration method on the source Bean. For example:

button.addPropertyChangeListener(aButtonListener);
Or, you can use an adapter class to catch the property change event, and subsequently call the correct method within the listener object. Here is an example taken from comments in the beans/demo/sunw/demo/misc/ChangeReporter.java file.
OurButton button = new OurButton();
...
PropertyChangeAdapter adapter = new PropertyChangeAdapter();
...
button.addPropertyChangeListener(adapter);
...
class PropertyChangeAdapter implements PropertyChangeListener
{
  public void propertyChange(PropertyChangeEvent e)
  {
    reporter.reportChange(e);
  }
}

Bound Properties in the BeanBox

The BeanBox handles bound properties by using an event hookup adapter class. The OurButton and ChangeReporter Beans can be used to illustrate this technique. To see how this works, take the following steps:

  1. Drop OurButton and ChangeReporter instances on the BeanBox.
  2. Select the OurButton instance and choose the Edit|Events|propertyChange|propertyChange menu item.
  3. Connect the rubber band line to the ChangeReporter instance. The EventTargetDialog will be displayed.
  4. Choose reportChange from the EventTargetDialog. The event hookup adapter source will be generated and compiled
  5. Select OurButton and change some of it's properties. You will see change reports in ChangeReporter.

Behind the scenes the BeanBox generated the event hookup adapter. This adapter implements the PropertyChangeListener interface, and also generates a propertyChange() method implementation that calls the ChangeReporter.reportChange() method. Here's the generated adapter source code:

// Automatically generated event hookup file.

package tmp.sunw.beanbox;
import sunw.demo.misc.ChangeReporter;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;

public class ___Hookup_14636f1560 implements
            java.beans.PropertyChangeListener, java.io.Serializable {

    public void setTarget(sunw.demo.misc.ChangeReporter t) {
        target = t;
    }

    public void propertyChange(java.beans.PropertyChangeEvent arg0) {
        target.reportChange(arg0);
    }

    private sunw.demo.misc.ChangeReporter target;
}

The ChangeReporter Bean need not implement the PropertyChangeListener interface; instead, the BeanBox generated adapter class implements PropertyChangeListener, and the adapter's propertyChange() method calls the appropriate method in the target object (ChangeReporter).

The BeanBox puts the event adapter classes in the beans/beanbox/tmp/sunw/beanbox directory. When an adapter class is generated, you can view the adapter source in that directory.


Previous | Next | Trail Map | JavaBeans Tutorial | Writing Advanced Beans