Writing JavaBeans Components

«« Previous
Next »»

Writing JavaBeans components is surprisingly easy. You don't need a special tool and you don't have to implement any interfaces. Writing beans is simply a matter of following certain coding conventions. All you have to do is make your class look like a bean — tools that use beans will be able to recognize and use your bean.

However, NetBeans provides some features that make it easier to write beans. In addition, the Java SE API includes some support classes to help implement common tasks.

The code examples in this lesson are based on a simple graphic component called FaceBean.

FaceBean source code only:
FaceBean.java

Entire NetBeans project including FaceBean source code:
FaceBean.zip

A bean is a Java class with method names that follow the JavaBeans guidelines. A bean builder tool uses introspection to examine the bean class. Based on this inspection, the bean builder tool can figure out the bean's properties, methods, and events.

The following sections describe the JavaBeans guidelines for properties, methods, and events. Finally, a section on BeanInfo shows how you can customize the developer's experience with your bean.

01. Properties


To define a property in a bean class, supply public getter and setter methods. For example, the following methods define an int property called mouthWidth:

public class FaceBean {
    private int mMouthWidth = 90;

    public int getMouthWidth() {
        return mMouthWidth;
    }
 
    public void setMouthWidth(int mw) {
        mMouthWidth = mw;
    }
}

A builder tool like NetBeans recognizes the method names and shows the mouthWidth property in its list of properties. It also recognizes the type, int, and provides an appropriate editor so the property can be manipulated at design time.

This example shows a property than can be read and written. Other combinations are also possible. A read-only property, for example, has a getter method but no setter. A write-only property has a setter method only.

A special case for boolean properties allows the accessor method to be defined using is instead of get. For example, the accessor for a boolean property running could be as follows:

public boolean isRunning() {
    // ...
}

Various specializations of basic properties are available and described in the following sections.

Indexed Properties

An indexed property is an array instead of a single value. In this case, the bean class provides a method for getting and setting the entire array. Here is an example for an int[] property called testGrades:

public int[] getTestGrades() {
    return mTestGrades;
}

public void setTestGrades(int[] tg) {
    mTestGrades = tg;
}
For indexed properties, the bean class also provides methods for getting and setting a specific element of the array.

public int getTestGrades(int index) {
    return mTestGrades[index];
}

public void setTestGrades(int index, int grade) {
    mTestGrades[index] = grade;
}

Bound Properties

A bound property notifies listeners when its value changes. This has two implications:

1. The bean class includes addPropertyChangeListener() and removePropertyChangeListener() methods for managing the bean's listeners.
2. When a bound property is changed, the bean sends a PropertyChangeEvent to its registered listeners.

PropertyChangeEvent and PropertyChangeListener live in the java.beans package.

The java.beans package also includes a class, PropertyChangeSupport, that takes care of most of the work of bound properties. This handy class keeps track of property listeners and includes a convenience method that fires property change events to all registered listeners.

The following example shows how you could make the mouthWidth property a bound property using PropertyChangeSupport. The necessary additions for the bound property are shown in bold.

import java.beans.*;

public class FaceBean {
    private int mMouthWidth = 90;
    private PropertyChangeSupport mPcs =
        new PropertyChangeSupport(this);

    public int getMouthWidth() {
        return mMouthWidth;
    }
 
    public void setMouthWidth(int mw) {
        int oldMouthWidth = mMouthWidth;
        mMouthWidth = mw;
        mPcs.firePropertyChange("mouthWidth",
                                   oldMouthWidth, mw);
    }

    public void
    addPropertyChangeListener(PropertyChangeListener listener) {
        mPcs.addPropertyChangeListener(listener);
    }
 
    public void
    removePropertyChangeListener(PropertyChangeListener listener) {
        mPcs.removePropertyChangeListener(listener);
    }
}

Bound properties can be tied directly to other bean properties using a builder tool like NetBeans. You could, for example, take the value property of a slider component and bind it to the mouthWidth property shown in the example. NetBeans allows you to do this without writing any code.

Constrained Properties

A constrained property is a special kind of bound property. For a constrained property, the bean keeps track of a set of veto listeners. When a constrained property is about to change, the listeners are consulted about the change. Any one of the listeners has a chance to veto the change, in which case the property remains unchanged.

The veto listeners are separate from the property change listeners. Fortunately, the java.beans package includes a VetoableChangeSupport class that greatly simplifies constrained properties.

Changes to the mouthWidth example are shown in bold:

import java.beans.*;

public class FaceBean {
    private int mMouthWidth = 90;
    private PropertyChangeSupport mPcs =
        new PropertyChangeSupport(this);
    private VetoableChangeSupport mVcs =
        new VetoableChangeSupport(this);

    public int getMouthWidth() {
        return mMouthWidth;
    }
 
    public void
    setMouthWidth(int mw) throws PropertyVetoException {
        int oldMouthWidth = mMouthWidth;
        mVcs.fireVetoableChange("mouthWidth",
                                    oldMouthWidth, mw);
        mMouthWidth = mw;
        mPcs.firePropertyChange("mouthWidth",
                                 oldMouthWidth, mw);
    }

    public void
    addPropertyChangeListener(PropertyChangeListener listener) {
        mPcs.addPropertyChangeListener(listener);
    }
 
    public void
    removePropertyChangeListener(PropertyChangeListener listener) {
        mPcs.removePropertyChangeListener(listener);
    }

    public void
    addVetoableChangeListener(VetoableChangeListener listener) {
        mVcs.addVetoableChangeListener(listener);
    }
 
    public void
    removeVetoableChangeListener(VetoableChangeListener listener) {
        mVcs.removeVetoableChangeListener(listener);
    }
}

Development Support in NetBeans

The coding patterns for creating bean properties are straightforward, but sometimes it's hard to tell if you are getting everything correct. NetBeans has support for property patterns so you can immediately see results as you are writing code.

To take advantage of this feature, look at the Navigator pane, which is typically in the lower left corner of the NetBeans window. Normally, this pane is in Members View mode, which shows all the methods and fields defined in the current class.

Click on the combo box to switch to Bean Patterns view. You will see a list of the properties that NetBeans can infer from your method definitions. NetBeans updates this list as you type, making it a handy way to check your work.

In the following example, NetBeans has found the read-write mouthWidth property and the read-write indexed testGrades property. In addition, NetBeans has recognized that FaceBean allows registration of both PropertyChangeListeners and VetoableChangeListeners.

Oracle Java Tutorials and Materials, Oracle Java Guides

02. Methods


A bean's methods are the things it can do. Any public method that is not part of a property definition is a bean method. When you use a bean in the context of a builder tool like NetBeans, you can use a bean's methods as part of your application. For example, you could wire a button press to call one of your bean's methods.

03. Events


A bean class can fire off any type of event, including custom events. As with properties, events are identified by a specific pattern of method names.

public void add<Event>Listener(<Event>Listener a)
public void remove<Event>Listener(<Event>Listener a)

The listener type must be a descendant of java.util.EventListener.

For example, a Swing JButton is a bean that fires action events when the user clicks on it. JButton includes the following methods (actually inherited from AbstractButton), which are the bean pattern for an event:

public void addActionListener(ActionListener l);
public void removeActionListener(ActionListener l);

Bean events are recognized by builder tools and can be used in wiring components together. For example, you can wire a button's action event to make something happen, like invoking another bean's method.

04. Using a BeanInfo


Beans, especially graphic components, can have a dizzying number of properties. If your class inherits from Component, or JComponent, or other Swing classes, it will have over one hundred properties already. Although a builder tool like NetBeans makes it easy to edit bean properties, it can be hard to find the right properties to edit, especially for inexperienced programmers.

Overview of BeanInfo

A BeanInfo is a class that changes how your bean appears in a builder tool. A builder tool can query the BeanInfo to find out which properties it should display first and which should be hidden.

The BeanInfo class for your bean should have the same name as the bean class, with BeanInfo appended. For example, the FaceBean class has a corresponding FaceBeanBeanInfo class that describes it.

Although it is possible to implement a BeanInfo class "by hand," you will find it is much easier to use a tool like NetBeans to edit the BeanInfo.

Creating a BeanInfo in NetBeans

In the Projects pane, Control-click on the name of your bean class and choose BeanInfo Editor... from the popup menu.

Oracle Java Tutorials and Materials, Oracle Java Guides

NetBeans notices you don't have a BeanInfo and asks if you want to create one. Click Yes.

Oracle Java Tutorials and Materials, Oracle Java Guides

NetBeans creates a new class and drops you into the source code editor. Click on Designer to switch to a visual editor.

Oracle Java Tutorials and Materials, Oracle Java Guides

Select properties from the list in the left side of the visual editor, then edit its attributes in the right side. If you don't want a particular property to appear to a developer using a builder tool, click Hidden. To signal that a property should be shown before others, click Preferred. You can also indicate if a property is bound or constrained.

You can provide similar information for the bean's event sources and methods.

When a builder tool loads your bean class to add it to a palette, it will automatically find the corresponding BeanInfo and use it to decide how to present your bean to the developer.

«« Previous
Next »»