by Mark Johnson

“Double Shot, Half Decaf, Skinny Latte” — Customize your Java

how-to
Sep 1, 199723 mins
Core JavaJava

How to tailor JavaBeans to fit your application

Consider the following exchange:

Sally: I’d like the chef salad please with oil and vinegar on the side, and the apple pie a la mode.

Waitress: Chef and apple a la mode.

Sally: But I’d like the pie heated, and I don’t want the ice cream on top. I want it on the side, and I’d like strawberry instead of vanilla if you have it. If not, then no ice cream, just whipped cream, but only if it’s real. If it’s out of the can, then nothing.

Waitress: Not even the pie?

Sally: No, just the pie, but then not heated.

This was Meg Ryan in the role of Sally Albright in the movie When Harry Met Sally.

Sally knows exactly what she wants. As an application designer, so do you. Fortunately, no matter how complex your customization requirements may be, JavaBeans is up to the task. Customization allows an application developer to control the behavior and appearance of a software component. Making a component customizable greatly extends where it can be used. For example, consider a Spreadsheet bean. If such a bean insisted on taking up the whole screen, or clashed with the color scheme of your application, or only displayed its data in hexadecimal, you might not be able to use it — even if it provided all of the other functionality you needed. A customizable bean has properties (like number of cells, color, and so on) that a developer can view and modify, custom-fitting the bean to the application.

The JavaBeans Specification (hereafter known as “the JavaBeans Spec”) includes features that make identifying and modifying component properties extremely easy in simple cases, and provides extensions for more complex situations.

This month, we’ll explore the JavaBeans customization interface. You’ll learn about component properties, and how to write your beans so that integrated development environments (IDEs) can present those properties to applications developers. We’ll discuss bound and constrained properties, which help beans communicate or maintain consistency. We’ll also touch on special-case customizers for situations in which you want more control over customization. Finally, we’ll start using the BeanBox, Sun’s free testbed for JavaBeans. (For more on the BeanBox, see my companion article in this month’s JavaWorld: “The BeanBox: SunSoft’s JavaBeans test container.”)

What is customization?

Software components typically are general-purpose “chunks” of functionality and data, written to be usable in a variety of situations. (For an introduction to JavaBeans, see last month’s column in JavaWorld, “A walking tour of JavaBeans.”) What’s important about customization? A software component can be used in a wider range of applications when the application developer has control over its appearance and behavior. For example, a PushButton class wouldn’t be very useful if its text label were always the word “Button,” and its associated action were always, say, to reboot your machine (although with some operating systems, this might be one of your most useful tools).

Even a component as simple as a lowly PushButton may have many attributes that a developer might want to control, including:

  • whether or not it is enabled
  • action
  • background color
  • text color
  • size
  • position
  • shape
  • label text (or maybe an icon instead of a label)
  • the sound file to play when the button is pressed

Complex components have even more involved customization requirements. Customizing a remote database connection might entail selecting from a list of available servers (information available only at run time), choosing a protocol (ditto), specifying user name and password, and setting up access through a firewall.

Properties of a bean

In general, customization means configuring the internal state of a bean so that it appears and behaves properly in the situation in which it is being used. The individual elements of this internal state (color, size, password string, and so on) are called properties in the JavaBeans Spec. A bean’s properties may be examined and modified by using methods called accessors. An accessor is either a getter method to read a property’s value, or a setter method to change it. The PushButton bean, then, might have a method called String getLabel(), which returns the bean’s current label, and void setLabel(String newLabel), which sets it. A property with only a getter method can be considered read-only.

Why not simply access the data members inside the bean class and modify or read them directly, instead of writing these accessors? Because there’s no guarantee that the properties correspond directly to data members inside the bean. A bean’s label property, for example, may be an AWT Label object; but then again, it may not be. Maybe the label text is read from a database, maybe it’s the label of another bean, or maybe the bean makes up a label only if it’s asked to do so! An accessor method is a uniform interface to a property of a bean that hides how that property is implemented. This is simply good object-oriented programming practice because it decreases the dependencies or “coupling” between objects.

An IDE that complies with the JavaBeans Spec knows how to analyze a bean to discover its properties. It also knows how to create a visual representation for each property type, called a property editor, to allow the application developer to modify the properties at design time. When the developer drops a bean into an application, the IDE draws the bean on the panel. It then presents a property sheet, which is simply a list of all of the bean’s properties, with associated editors for each property. The IDE will call all of the getter methods so that the property sheet contains the bean’s current property values. If the developer changes a property in the property sheet, the IDE calls the corresponding setter method to update the associated property of the selected bean.

For beans of low to moderate complexity, configuring a bean at design time by calling its setter methods is often enough. To support the higher degree of customization control required by more complex beans, though, the Spec defines a customizer class that developers may extend and include with a bean. This leaves the door wide open for customization of any sort: sophisticated color pickers, graphical network configuration wizards, even a VRML interface if you’re up to writing one! Actually, the property sheet described above can be considered a customizer that is automatically generated by an IDE. You’ll see this pattern often in the JavaBeans framework: Simple things (in this case, simple property types for which property editors already exist) usually entail little or no work, but access is provided “under the hood” for more complicated situations.

How to make beans customizable

The JavaBeans framework makes creating beans with customizable properties a snap; much of the time, there’s no need to write any code at all! This is because the JavaBeans Spec defines a naming convention that IDEs use to infer which methods correspond to properties. The Spec calls these conventions design patterns (which is unfortunate, because the phrase “design pattern” means something else entirely in architecture and in object-oriented programming — see Resources below). Semantic nit-picking aside, the principle is simple: The name, the return type, and the argument types (the signature, in OO parlance) determine the names and types of the properties. A getter method for a property called Property of type TYPE is defined as TYPE getProperty(), and the setter method for this property is void setProperty(TYPE newValue). When an IDE loads a bean, it uses the JDK 1.1 reflection mechanism to scan all of the bean’s methods, looking for methods whose names start with get and set. The IDE adds the properties it finds to the property sheet so the developer can customize the bean.

Time to customize a bean

Let’s look at a concrete example of bean customization by extending the nascent BarChart bean from last month. A quick peek at the source code reveals a lucky break: The BarChart bean already has getter and setter methods that conform to the Spec’s design pattern — void setPercent(int iPercent) and int getPercent(). In other words, this bean already has a property: percent. Let’s load the BarChart bean into the BeanBox and see what happens.

To the left of the figure is a panel containing the available beans for placement in the BeanBox. In the center is the BeanBox itself, with the BarChart selected, and to the right is the property sheet for the BarChart. The property sheet has five properties: foreground and background (of type Color), font (of type Font), percent (an integer), and name (a String). When the BeanBox loaded the BarChart, it found the methods int getPercent() and void setPercent(int iPercent) and recognized percent as a property of the bean. It then added that property to the property sheet, along with a property editor for an integer (the textbox to the right of the label percent). The getPercent() function was called to fill in the value in the property editor (in this case, the value was 0). This process occurred for all of the properties on the property sheet.

But wait! BarChart only defines percent as a property. Where did all those other properties come from? Since BarChart is defined as:

public class BarChart extends Canvas implements Serializable

BarChart inherits java.awt.Canvas, which inherits java.awt.Component, which defines (you guessed it) Color getForeground(), void setForeground(Color), and so on. This means that, handily, if you subclass a bean, what you get is a new bean with all the parent bean’s properties.

If you change the property in the BeanBox’s property sheet, the bean is updated on the fly. Input “62” in the property editor for percent and the BeanBox responds accordingly, as shown in this figure:

The IDE (in this case, the BeanBox) detects that the value in the property editor for percent changed, and updates the BarChart’s percent by calling setPercent().

All this is fine, as long as your application requires a BarChart of exactly 25 by 150 pixels, with a blue background, a two-pixel black border, and red flooding to the percentage chosen.

Fortunately, we’ve got the source code for this bean, so let’s add some new properties: Colors fillColor, floodColor, and borderColor; and ints borderWidth, barHeight, and barWidth. As an example, let’s add the floodColor() accessors. We previously defined the flood color as private Color fgColor_ = Color.red. Let’s rename it floodColor to avoid confusion with java.awt.Component‘s foreground and background properties, and write accessors for it:

private Color floodColor_ = Color.red;
public void setFloodColor(Color floodColor)
{
    floodColor_ = floodColor;
}
public Color getFloodColor()
{
    return floodColor_;
}

There’s no more to it than that. Adding similar accessors for the other properties results in a new class file containing a flexible new bean. (Check out the source code for the new bean.)

Now that our BarChart beans are customizable, we can make them look any way we like, as shown here:

Here we see four BarChart beans, each customized with a different color scheme and filled to a different percentage. Adding just a few methods to the BarChartBean class gives the application developer enormous flexibility. (Judging from the hideousness of some of the color schemes, maybe we’ve provided a bit too much flexibility!)

This works well, as long as your properties are already of built-in types — or you don’t mind being limited to typing strings and picking colors. What if a property type were of a type you had defined yourself? It would be cool if the BarChart had a direction property indicating which direction the BarChart should grow. Its valid values might be UP, DOWN, LEFT, and RIGHT, but how would you customize that?

The nitwit answer is: “Make the user type in an integer 0-3 to indicate the direction.” The smart answer appears in the JavaBeans Spec: Write your own property editor. The interface java.beans.PropertyEditor and the utility class java.beans.PropertyEditorSupport allow the beans developer to specify a property editor for a “custom” type like the direction type we’ve just described. Custom property editors can even be graphical: A NetworkConfiguration bean might have a HostConnections property that could be configured by drawing connections between servers with a mouse. How to write a property editor class and link it to a bean would be a good subject for a future column, if there’s sufficient interest. Write and let me know! (See my bio below for contact information.)

One final note on basic properties. Properties may be defined as arrays of values instead of just scalars. Such properties are known as indexed properties, and differ from their scalar counterparts by having different signatures for their accessor methods. The getter and setter methods are “overloaded”: You can access a property either by individual element:

void setProperty(int index, TYPE value)
TYPE getProperty(int index)

or by an entire array at once:

void setProperty(TYPE valueList[])
TYPE[] getProperty()

For example, if you had a Polygon3D bean that drew itself onto a canvas, you could access the Polygon3D’s points individually:

Point3D newPoint = new Point3D(0, 25, 0);
myPolygon.setPoint(2, newPoint); // Throws exception if < 3 points

or set a whole array at once:

Point3D p1 = new Point3D(0, 10, 0);
Point3D p2 = new Point3D(10, 1, 15);
Point3D p3 = new Point3D(15, 0, 25);
Point3D[] points = { p1, p2, p3 };
myPolygon.setPoint(points);

Bound and constrained properties

As painful as being bound or constrained may sound, it’s really not all that bad. In fact, it can make your job easier by freeing you of all the messy details involved in updating related GUI elements when one property value changes. Or it can free you from having to maintain a consistent state between (as opposed to within) beans. A bound property is simply a bean property whose setter method notifies other objects (called listeners) when its value changes, allowing those other beans to take some action. A constrained property works similarly, except that the listeners also have the option of “vetoing” any change to the property that they don’t like. To understand how to use these property types, though, it’s necessary to understand the basics of the new JDK 1.1 event-processing structure.

Event listeners

A Java component notifies other components of changes to its properties by using an event listener interface, a new concept that appeared with JDK 1.1. When a property changes, the object whose property changed creates an event object containing information about the property, and passes it to all other components that have expressed an interest in that property.

In the old event model of the AWT, event processing was based on inheritance: To capture an event and handle its processing, you had to subclass something that already handled that event and change its behavior. This made it difficult to create new event types and unnecessarily limited how they could be processed. The event-listener approach bases event processing on delegation (or association): Objects that generate events maintain a list of other objects that are interested in that event type, and they “fire” events at those objects as the events occur.

An (conceptual) example of an event listener

Let’s use Senators (yes, Senators) as an example.

In this diagram we have a situation whereby four objects (a Reporter, a Strategist, an Aide, and a Crank) all want to know when a particular Senator’s salary changes (salary is a property of the Senator class). The Senator is required (presumably by law) to notify any interested parties when his salary changes. The Senator provides an event listener registration method called (in this case) void addSalaryListener(SalaryListener l). Any object that is passed to this method is added to a “listener list” that the Senator maintains for salary change events. In addition to giving Our Humble Servant a fat pay hike, the setSalary() method also creates a SalaryChangedEvent object containing the salary change amount and passes that event to each listener by calling the listener’s method void salaryChanged(SalaryChangedEvent event). The event source (the Senator) is said to “fire” a SalaryChangedEvent at each of its listeners by passing the event to the listener’s salaryChanged() method. For their part, the listeners implement class-specific functionality in response to the event: The Reporter speculates, the Strategist spin-doctors, the Aide agitates for her own raise, and the Crank writes rambling, delusional letters to the Post (New York, not Washington).

The actual amount of the pay raise is encoded in the SalaryChangedEvent object that the Senator sends to all listeners. Let’s create a subclass of java.util.EventObject to hold the amount of the Senator’s raise:

// Encapsulates salary change
public class SalaryChangedEvent extends java.util.EventObject
{
    double raiseAmount_;
    void setRaiseAmount(double raiseAmount) {
        raiseAmount_ = raiseAmount;
    }
    // …etc…
}

Now, we define the interface SalaryListener, which extends java.util.EventListener to process a SalaryChangedEvent:

interface SalaryChangedListener extends java.util.EventListener
{
    void salaryChanged(SalaryChangedEvent event);
}

Now, any class can implement the SalaryListener interface, enabling it to register itself with a Senator and receive his or her SalaryChangedEvents:

class Crank extends Crackpot implements SalaryListener
{
    // register interest in salary by adding self to Senator's
    // list of salary listeners
    public void Crank(Senator senatorToHarass) {
        // place myself on this senator's list of listeners.
        senatorToHarass.addSalaryChangedListener(this);
    }
    // the senator calls this method when his/her salary property changes
    public void salaryChanged(SalaryChangedEvent event) {
        double theRaise = event.getRaiseAmount();
        // ramble ad nauseam
    }
}

You can see from the figure that, when the Senator’s salary property changes, the Senator object creates a SalaryChangedEvent, and then passes that event to every listener on its list.

Bound properties

Now that you understand event listeners, we can discuss how they apply to bound properties. An event listener interface called PropertyChangeListener and an event type called PropertyChangeEvent are defined in java.beans to handle bound property change notification. The bean is the event source (the Senator), and the listeners are any objects that have an interest in the change in a property (salary). Any object that is interested in the bound properties of event sources may implement the PropertyChangeListener interface, thereby becoming a listener. Any object that can be a PropertyChangeEvent source (for example, a Senator) implements the methods:

void addPropertyChangeListener(PropertyChangeListener l)
void removePropertyChangeListener(PropertyChangeListener l)

thereby making available properties for binding. The setter method for any “bound” property (such as salary) is then responsible for creating a PropertyChangeEvent and passing it to all registered listeners after changing the property in question. This is a more general solution than the Senator example, because there’s only one type of PropertyChangeEvent, not one type for each specific property (like salary).

To make all of this a bit easier, the JavaSoft team has created a thread-safe class called java.beans.PropertyChangeSupport, which manages lists of PropertyChangeListeners and fires all of the events for you. You can include a PropertyChangeSupport object as a member of your class, and then use it in your setter methods to handle all of your bound property change notification.

Constrained properties

Constrained properties work in exactly the same way as bound properties, except that (1) they change their state after notifying all listeners instead of before, and (2) the setter methods can veto proposed changes by throwing a PropertyVetoException. The event source passes a PropertyChangeEvent to all of its listeners, notifying them of a proposed change to a property. If any listener decides that the change doesn’t make sense, it throws a PropertyVetoException, and so the event source doesn’t update the property. The setter method has a slightly different signature in this case:

void setProperty(TYPE property) throws PropertyVetoException

Because of this, instead of PropertyChangeListener, the interface used for constrained properties is called VetoableChangeListener, and the support class used to make the process easier is VetoableChangeSupport.

An additional problem arises when a listener vetoes a change: Some of the listeners think the property has changed value (because their propertyChanged() method has been called) and the rest don’t. Because of this, when a listener vetoes a change, the setter method must go back and re-notify all listeners already notified that the object didn’t change its property after all. In general, setter methods ignore vetoes on these “change-back” notifications. The VetoableChangeSupport utility class handles all this for you, so it’s a good idea to use it unless there’s a compelling reason to do it yourself.

An example of a bound property

Now we’re going to make our BarChart class smarter by making it possible to bind the percent property of the BarChart bean to an integer property of another bean. The cool thing here is that we don’t know what property of what other bean the BarChart can be bound to; in fact, we don’t care. It’s completely general. Any class that can fire a PropertyChangeEvent with an integer value can be bound to this BarChart and (assuming the integer is between 0 and 100), the BarChart will faithfully display the quantity graphically. Let’s see how this is done.

We first need to make the BarChartBean class into an event listener. A class can only be a target for a PropertyChangeEvent if it is a PropertyChangeListener — that is, if it implements the java.beans.PropertyChangeListener interface. To implement this interface, a class need only implement a single method: public void propertyChange(PropertyChangeEvent event). When an event source object changes a property, it creates a PropertyChangeEvent and passes it to all listeners. (A Senator sends a letter to everyone on his mailing list announcing that he got a raise.) The PropertyChangeEvent object contains a reference to the object that sent it, the name of the property being changed, and the old and new values of the property, stored as objects (meaning integers must be stored as Integers, and so on).

To make the BarChartBean into a PropertyChangeListener, we add an interface and implement it:

public class BarChartBean
    extends Canvas
    implements Serializable, PropertyChangeListener
{
    // Respond to a property change event for the property
    // "value" by updating my value to a new value.
    public void propertyChange(PropertyChangeEvent event)
    {
        Integer newValue = (Integer)event.getNewValue();
        setPercent(newValue.intValue());
    }
}

All this says is, “Whenever the BarChartBean receives a PropertyChangeEvent, get the newValue() of the property and set the percent property to that number.” Simple as that.

Now we need a class that can fire events at our BarChart bean. I’ve created a simple bean called an IntBox, which is a subclass of java.awt.TextField that accepts only digits and keeps track of its numeric value. (You can check out the source code if you like.) The IntBox bean has a special trait: It implements functions called public void addPropertyChangeListener(PropertyChangeListener listener) and public void removePropertyChangeListener(PropertyChangeListener listener). Any class (like BarChart) that implements the PropertyChangeListener interface can call these functions to add/remove itself from the list of classes “listening” from PropertyChangeEvents from the IntBox. Here’s the implementation of these methods:

public class IntBox extends TextField implements Serializable
{
    PropertyChangeSupport pcs_;    //… constructor, etc….
    // Allow other objects to register interest in my bound properties
    public void addPropertyChangeListener(PropertyChangeListener listener)
    {
    pcs_.addPropertyChangeListener(listener);
    }
    // Allow other objects to remove their interest in my bound properties
    public void removePropertyChangeListener(PropertyChangeListener listener)
    {
    pcs_.removePropertyChangeListener(listener);
    }

The utility class PropertyChangeSupport makes it simple to keep track of listeners by maintaining the list for you. Now, when the value property of the IntBox changes (that is, when setValue() is called), we want to tell all the listeners about it. So, we put a single extra line in setValue() to create and fire the event object:

    // Set new value
    public void setValue(int value)
    {
    int oldValue = prev_;
    setText(Integer.toString(value));
    int newValue = getValue();
   pcs_.firePropertyChange("value", new Integer(oldValue),
                new Integer(newValue));

    prev_ = newValue;
    }

This code is pretty straightforward: We get the new value and then call the firePropertyChange() method of our PropertyChangeSupport object, giving it the name of the property we’re changing and the previous and new values of the property. We then keep track of the previous value so we can pass it in again on our next call. The method firePropertyChange() creates a PropertyChangeEvent object and passes it to all listeners, unless the old and new values are the same. The PropertyChangeEvent has the source object and the property name embedded in it so that the listeners can decide what to do based on who changed what.

Put ’em all together

So, what’s left to do? Let’s wire these beans together and see if they work. I’ve created a class called ColorBar, which contains an IntBox bean and a BarChartBean bean (see the source code). You may want to download the file ColorBar.jar and load it into the BeanBox so you can see this in action. The ColorBar creates the IntBox and BarChartBean components in its constructor, and then it does this:

intBox_.addPropertyChangeListener(barChartBean_);

This is where the rubber meets the road. The BarChartBean, being a PropertyChangeListener, has just been added to the list of objects that are to be notified whenever the IntBox‘s value property is set. The sequence of events is simple:

  1. The user types a number into the IntBox and hits .

  2. IntBox.processKeyEvent() gets the current integer value out of the box and calls setValue().

  3. IntBox.setValue() updates the property value, and then calls firePropertyChange().

  4. firePropertyChange() creates a PropertyChangeEvent object and passes it to BarChartBean.propertyChanged().

  5. BarChartBean.propertyChanged() sets the BarChartBean‘s percent value, and the BarChart updates (assuming that the amount entered was between 0 and 100.

In the BeanBox, the result looks like this:

Load this bean into the BeanBox and try it yourself!

There is one problem with this set-up: The BarChart only accepts input from 0 to 100, but the IntBox can set its value property to any positive integer. This is a job for the constrained properties that we discussed before. If the BarChart were to implement VetoableChangeListener, and the IntBox were to use a VetoableChangeSupport object, then the BarChart could throw an exception in its propertyChange() method any time the new value was out of range, and the IntBox would be constrained from setting its value to the new quantity. Only numbers that the BarChart accepted would be allowed. As an exercise, try modifying the BarChartBean and the IntBox to get this to work.

Conclusion

There is a lot more to cover just on the topic of properties. In particular, since the BeanBox understands the PropertyChangeListener interface, it can generate classes automatically to bind a property of one bean to another property of a second one. Try it yourself: Put a BarChartBean and an IntBox in the BeanBox, select the IntBox, and then select Edit->Bind Property… on the menu. You’ll find you can build the ColorBar bean graphically.

This month, we’ve discussed properties and how they’re used to customize beans. We discussed event listener interfaces, and went over bound and constrained properties. Then we bound a property of one bean to a property of another using the PropertyChangeListener interface.

Next month, we’ll go into more detail about how events work in JDK 1.1, and use those new principles to wire beans together in interesting and flexible ways.

Mark Johnson has a BS in Computer and Electrical Engineering from Purdue University (1986). He has 15 years of experience programming in C and two years in C++, and is a fanatical devotee of the Design Pattern approach in object-oriented architecture, of software components in theory, and of JavaBeans in practice. Over the past several years, he worked for Kodak, Booz-Allen and Hamilton, and EDS in Mexico City, developing Oracle and Informix database applications for the Mexican Federal Electoral Institute and for Mexican Customs. He spent the last year working at NETdelivery, an Internet startup now in Boulder, CO. Mark is a dyed-in-the-wool Unix programmer, and sees Java as the missing link between the now ubiquitous desktop client systems and open, distributed, and scalable enterprise back-ends. He currently works as a designer and developer for Object Products in Fort Collins, CO.