Customizing with BeanInfo

So far, everything NetBeans has known about our beans has
been determined by low-level reflection—that is, by looking at the methods
of our classes. The java.Beans.Introspector
class gathers information on a bean using reflection, then analyzes and
describes a bean to any tool that wants to know about it. The
introspection process works only if the class follows the JavaBeans naming
conventions for its methods; furthermore, it gives us little control over
exactly what properties and events appear in NetBeans menus. For example,
we’ve seen that NetBeans by default shows all the stuff we inherit from
the base Swing component. We can change that by creating BeanInfo classes for our beans. A BeanInfo class provides the JavaBeans
introspector with explicit information about the properties, methods, and
events of a bean; we can even use it to customize the text that appears in
menus in NetBeans (and in other IDEs).

A BeanInfo class implements the
BeanInfo interface. That’s a
complicated proposition; in most situations, the introspector’s default
behavior is reasonable. Instead of implementing the BeanInfo interface, we extend the SimpleBeanInfo class, which implements all of
BeanInfo’s methods. We can override
specific methods to provide the information we want; when we don’t
override a method, we’ll get the introspector’s default behavior.

In the next few sections, we’ll develop the DialBeanInfo class that provides explicit
information about our Dial bean.

Getting Properties Information

We’ll start out by describing the Dial’s properties. To do so, we must implement
the getPropertyDescriptors() method. This
method simply returns an array of PropertyDescriptor objects—one for
each property we want to publicize.

To create a PropertyDescriptor,
call its constructor with two arguments: the property’s name and the
class. In the following code, we create descriptors for the Dial’s value, minimum, and maximum properties. We next call a few methods
of the PropertyDescriptor class to
provide additional information about each property. If our methods were
bound (generated PropertyChangeEvents
when modified), we’d call the setBound() method of
their PropertyDescriptors. Our code
is prepared to catch an IntrospectionException, which can occur if
something goes wrong while creating the property descriptors, such as
encountering a nonexistent method:

Perhaps the most useful thing about DialBeanInfo is that by providing explicit
information for our properties, we automatically hide other properties
that introspection might find. After compiling DialBeanInfo and packaging it with the
Dial, you’ll see that its JComponent properties no longer appear in the
NetBeans properties editor. (This has been the case all along if you
started with the precompiled example JAR.)

A PropertyDescriptor can
provide a lot of other information about a property: the names of the
accessor methods (if you decide not to use the standard naming
convention), information about whether the property is constrained, and
a class to use as a property editor (if the standard property editors
aren’t sufficient).

Getting events information

The Dial bean defines its own
event: the DialEvent. We’d like to
tell development tools about this event so that we can build
applications using it. The process for telling the world about our
event is similar to what we did previously: we add a method to the DialBeanInfo class called
getEventSetDescriptors(), which returns an
array of EventSetDescriptors.

Events are described in terms of their listener interfaces, not
in terms of the event classes themselves, so our getEventSetDescriptors() method creates a
descriptor for the DialListener
interface. Here’s the code to add to the DialBeanInfo class:

In this method, we create an EventSetDescriptor object: dial. The constructor for an EventSetDescriptor takes four arguments: the
class that generates the event, the name of the event (the name that
is displayed, by default, by a development tool), the listener class,
and the name of the method to which the event can be delivered. (Other
constructors let you deal with listener interfaces that have several
methods.) After creating the descriptor, we call the setDisplayName()
method to provide a friendly name to be displayed by development tools
such as NetBeans. (This overrides the default name specified in the
constructor.)

Just as the property descriptors we supply hide the properties
that were discovered by reflection, the EventSetDescriptors can hide the other
events that are inherited from the base component classes. In theory,
when you recompile DialBeanInfo,
package it in a JAR, and load it into NetBeans, you should see only
the two events that we have explicitly described: our own DialEvent and PropertyChangeEvent (displayed as “Dial
Adjusted” and “Bound property change”). Unfortunately, the current
version of NetBeans ignores this information.

Once we have an EventSetDescriptor, we can provide other
kinds of information about the event. For example, we can state that
the event is unicast, which means that it can
have only one listener.

Supplying icons

Some of the beans that come with NetBeans are displayed on the
palette with a cute icon. This makes life more pleasant for everyone.
To supply an icon for the BeanInfo
object we have been developing, we have it implement the getIcon() method. You
can supply up to four icons, with sizes of 16 × 16 or 32 × 32, in
color or monochrome. Here’s the getIcon() method for DialBeanInfo:

This method is called with a constant, indicating what kind of
icon is being requested; for example, BeanInfo.ICON_COLOR_16x16 requests a 16 × 16
color image. If an appropriate icon is available, it loads the image
and returns an Image object. If the
icon isn’t available, it returns null. For convenience, you can package the
images in the same JAR file as the bean and its BeanInfo class.

Though we haven’t used them here, you can also use a BeanInfo object to provide information about
other public methods of your bean (for example, array-valued
properties) and other features.

Creating customizers and property editors

JavaBeans lets you provide a customizer for
your beans. Customizers are objects that do advanced customization for
a bean as a whole; they let you provide your own GUI for tweaking your
bean. We won’t show you how to write a customizer; it’s not too
difficult, but it’s beyond the scope of this chapter. Suffice it to
say that a customizer must implement the java.beans.Customizer
interface and should extend Component (or JComponent) so that it can be
displayed.

Property editors are a way of giving the properties sheet
additional capabilities. For example, you could supply a property
editor to let you edit a property type that is specific to your bean.
You could provide a property editor that would let you edit an
object’s price in dollars and cents. We’ve already seen a couple of
property editors: the editor used for Color-valued properties is fundamentally the
same as a property editor you might write yourself. In addition, the
Molecule bean uses a property
editor to specify its moleculeName
property. A property editor isn’t quite as fancy
as a customizer, but describing it fully is also beyond the scope of
this chapter.

Again, describing how to write a property editor is also beyond
the scope of this chapter. However, it might help you to know that a
property editor must implement the PropertyEditor interface; it usually does so
by extending the PropertyEditorSupport class, which provides
default implementations for most of the methods.

The best content for your career. Discover unlimited learning
on demand for around $1/day.