The JavaTM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search

Trail: JavaBeans(TM)
Lesson: Properties

## Bound Properties

> > Here is a list of background reading to prepare you for learning bound properties:
> > - Chapter 7 of the `JavaBeans API Specification`
> > - `PropertyChangeListener` interface
> > - `PropertyChangeSupport` class
> > - `PropertyChangeEvent` class

> Sometimes when a Bean property changes, another object may want to be notified of the change, and react to the change. Whenever a bound property changes, notification of the change is sent to interested listeners.

> A Bean containing a bound property must maintain a list of property change listeners, and alert those listeners when the bound property changes. The convenience class `PropertyChangeSupport` implements methods that add and remove `PropertyChangeListener` objects from a list, and fires `PropertyChangeEvent` objects at those listeners when the bound property changes. Your Beans can inherit from this class, or use it as an inner class.

> An object that wants to listen for property changes must be able to add and remove itself from the listener list on the Bean containing the bound property, and respond to the event notification method that signals a property change. By implementing the `PropertyChangeListener` interface the listener can be added to the list maintained by the bound property Bean, and because it implements the `PropertyChangeListener.propertyChange` method, the listener can respond to property change notifications.

> 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 via the `propertyChange` method.

> The following sections provide the details of implementing bound properties.

### Implementing Bound Property Support Within a Bean

> To implement a bound property, 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 maintains the property change listener list and fires property change events. You can also make your class a `PropertyChangeSupport` subclass.

> 3. Implement methods to maintain the property change listener list. Since `PropertyChangeSupport` implements these methods, you 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)

>    The `firePropertyChange` method bundles its parameters into a `PropertyChangeEvent` object, and calls `propertyChange(PropertyChangeEvent pce)` on each registered listener. The old and new values are treated as `Object` values. If your property values are primitive types such as `int`, you must use the object wrapper version such as `java.lang.Integer`. Also, property change events are fired after the property has changed.

> When the BeanBox (or Beans-aware builder tool) recognizes the design patterns for bound properties within your Bean, you will see a `propertyChange` interface item when you select 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)

> This is the notification method that the source Bean calls on all property change listeners in its property change listener list.

> 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

> 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, for example, 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 a listener Bean.

> To register interest in receiving notification about a Bean property change, the listener Bean calls 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 property events as it handles all events: by using an event hookup adapter. Event hookup adapters classes are generated by builder tools when you connect an event source Bean to an event listener Bean. These objects interpose between event sources and event listeners to provide control and filtering over event delivery. Since an event listener can register with multiple listeners that fire the same event type, event hookup adapters can be used to intercept an event from a particular event source, and forward it to the correct event listener. This saves the event listener from implementing code that would examine each event to determine if it is from the correct source. See section 6.7 of the JavaBeans API Specification for a complete discussion of event hookup adapters.

> 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.

| Start of Tutorial > Start of Trail > Start of Lesson | Search