|
| |
How does the BeanBox, or any other similar builder tool,
determine a Bean's properties, events and methods?
It does it by using introspection, implemented in
the java.beans.Introspector
class. The Introspector
class uses the Java reflection mechanism, among other
mechanisms, to gather information about the Bean.
As one wag put it:
Although Java may be reflective, even
introspective, omphaloskepsis is still
not part of the core distribution.
So far, in the Beans we've developed, we've used the
naming conventions for getting and setting properties:
methods called getPropertyName
and setPropertyName,
etc.
Note: These naming conventions are inappropriately
and confusingly called
"design patterns" by JavaSoft.)
Sometimes, the information we supply implicitly, using
such conventions, is not enough for our needs, and sometimes
the reflection mechanism exposes more information than we
wish.
For example, remember the SimpleScatterPlot properties
sheet?
 |
There are a number of properties
that we'd rather not expose:
Plus, there are some properties that we would like
to be displayed, that aren't exposed at all, such as:
points,
because it is an indexed property, and its
type is not displayable
plotBounds,
because its type is not displayable
|
Additionally, there are times when we want to expose
something about our Beans that can't be represented by the
standard naming conventions.
The BeanInfo Interface
The Introspector
class provides a standard way for tools to learn about the
properties, events, and methods supported by a target Java
Bean.
For each of these three kinds of information, the Introspector will
separately analyze the Bean's class and superclasses looking
for either explicit or implicit information and use that
information to build a BeanInfo object that comprehensively
describes the target Bean.
For each class "Foo",
explicit information may be available if there exists a
corresponding "FooBeanInfo"
class that provides a non-null value when queried for the
information. The Introspector
class first looks for the BeanInfo
class by taking the full package-qualified name of the target
bean class and appending "BeanInfo"
to form a new class name. If it fails to find this class
within the classpath, then it takes the final classname
component of this name, and looks for that class in each of
the packages specified in the BeanInfo
package search path.
Thus, for a class such as "grover.myBeans.OurButton",
it would first look for a BeanInfo
class called "grover.myBeans.OurButtonBeanInfo".
If that fails, it would look in each package in the BeanInfo search
path for an OurButtonBeanInfo
class. With the default search path, this means looking for
"sun.beans.infos.OurButtonBeanInfo",
but the search path may be accessed and changed by the
caller, using the getBeanInfoSearchPath
and setBeanInfoSearchPath
methods.
If a class provides explicit BeanInfo
about itself then the Introspector
class adds that to the BeanInfo
information it obtained from analyzing any derived classes,
but it regards the explicit information as being definitive
for the current class and its base classes, and does not
proceed any further up the superclass chain.
If the Introspector
class doesn't find explicit BeanInfo
on a class, it uses low-level reflection to study the methods
of the class and apply standard design patterns to identify
property accessors, event sources, or public methods. It then
proceeds to analyze the class's superclass and add in the
information from it (and possibly on up the superclass
chain).
The BeanInfo
Interface specifies the following methods:
| Method |
Description |
| public
BeanInfo[] getAdditionalBeanInfo() |
Returns any additional BeanInfo
objects that are relevant to the associated Bean. |
| public
BeanDescriptor getBeanDescriptor() |
Returns the BeanDescriptor object |
| public
int getDefaultEventIndex() |
Returns the default event index |
| public
int getDefaultPropertyIndex() |
Returns the default property index |
| public
EventSetDescriptor[] getEventSetDescriptors() |
Returns the event set descriptors. |
| public
Image getIcon(int iconKind) |
Returns the specified icon for the
Bean |
| public
MethodDescriptor[] getMethodDescriptors() |
Returns the method descriptors. |
| public
PropertyDescriptor[] getPropertyDescriptors() |
Returns the property descriptors |
It is important to note that, if you provide a BeanInfo class for
your Bean, you do not have to specify everything about
your Bean in it. If your BeanInfo
class returns a null from any of these above methods, then
the Introspector
will use Reflection to provide that information for itself.
On the other hand, if you do supply some
information in your own BeanInfo
class, then that is considered definitive, and reflection
will not be used. This can get confusing at times,
if you don't understand it.
One interesting feature of the BeanInfo
class is that you can associate an icon with your
Bean, which can be used by a builder tool (and is used by the
BeanBox) at design time.
The Default Property
It is sometimes useful, in some contexts (such as a
scripting language, or similar) to define a default property.
If so, the BeanInfo class can return the index of the desired
default property.
The SimpleBeanInfo Class
To make things easier for you, the java.beans.SimpleBeanInfo
class implements the BeanInfo
interface, and provides method implementations that simply
return null. This is similar to the set of event Adapter classes each of which
implements its corresponding event Listener
interface, and provide method implementations which do
nothing. To create your BeanInfo
class, you merely extend the SimpleBeanInfo
class, and override what you need.
The SimpleBeanInfo
class provides one additional, and useful, method:
public Image loadImage(String resourceName)
This is a utility method to help in loading icon images.
It takes the name of a resource file associated with the
current object's class file and loads an image object from
that file. (Typically images will be GIFs.)
The SimpleBeanInfo
class' implementation of the getDefaultPropertyIndex
method returns -1, indicating
that there is no default property.
The FeatureDescriptor Class
The FeatureDescriptor class is the common baseclass for
the PropertyDescriptor,
EventSetDescriptor,
and MethodDescriptor
classes, etc. It supports some common information that can be
set and retrieved for any of the introspection descriptors.
In addition it provides an extension mechanism so that
arbitrary attribute/value pairs can be associated with a
design feature.
It contains the following methods:
| Method |
Description |
| public
Enumeration attributeNames() |
Returns an enumeration of the
locale-independent names of any attributes that have
been registered with setValue. |
| public
String getDisplayName() |
Returns the localized display name
for the property/method/event. This defaults to the
same as its programmatic name from getName. |
| public
String getName() |
Returns the programmatic name of the
property/method/event |
| public
String getShortDescription() |
Returns a localized short
description associated with this
property/method/event. This defaults to be the
display name. |
| public
Object getValue(String attributeName) |
Retrieve a named attribute with this
feature. |
| public
boolean isExpert() |
Returns true if this feature is
intended for use by experts only.
The "expert" flag is used to distinguish
between those features that are intended for expert
users from those that are intended for normal users. |
| public
boolean isHidden() |
Returns true if this feature should
be hidden from human users.
The "hidden" flag is used to identify
features that are intended only for tool use, and
which should not be exposed to humans. |
| public
void setDisplayName(String displayName) |
Sets the localized display name for
the property/method/event. |
| public
void setExpert(boolean expert) |
Sets the "expert" flag. |
| public
void setHidden(boolean hidden) |
Sets the "hidden" flag. |
| public
void setName(String name) |
Sets the programmatic name of the
property/method/event. |
| public
void setShortDescription(String text) |
Associates a short descriptive
string with a feature. Normally these descriptive
strings should be less than about 40 characters. |
| public
void setValue(String attributeName, Object value) |
Associates a named attribute with
this feature. |
The BeanDescriptor Class
A BeanDescriptor,
a subclass of FeatureDescriptor,
provides global information about a Bean. It is used to
desribe the classes that implement the Bean and the Bean
customizer, if any.
BeanDescriptor
contains the following methods, in addition to those present
in FeatureDescriptor:
| Method |
Description |
| public
BeanDescriptor(Class beanClass, Class
customizerClass) |
Constructs a BeanDescriptor for a
bean that has a customizer. |
| public
BeanDescriptor(Class beanClass) |
Constructs a BeanDescriptor for a
bean that doesn't have a customizer. |
| public
Class getBeanClass() |
Returns the Class object for the
bean. |
| public
Class getCustomizerClass() |
Returns the Class object for the
bean's customizer. This may be null if the bean
doesn't have a customizer. |
The PropertyDescriptor Class
A PropertyDescriptor,
a subclass of FeatureDescriptor,
describes one property that a Java Bean exposes.
PropertyDescriptor
contains the following methods, in addition to those present
in FeatureDescriptor:
| Method |
Description |
public
PropertyDescriptor(String propertyName, Method
getter, Method setter)
throws IntrospectionException |
Constructs a PropertyDescriptor,
using the name of a simple property, and Method
objects for reading and writing the property. |
public
PropertyDescriptor(String propertyName,
Class beanClass, String getterName, String
setterName)
throws IntrospectionException |
Constructs a PropertyDescriptor,
using the name of a simple property, and method names
for reading and writing the property. |
public
PropertyDescriptor(String propertyName,
Class beanClass)
throws IntrospectionException |
Constructs a PropertyDescriptor for
a property that follows the standard Java convention
by having getFoo and setFoo accessor methods. Thus if
the argument name is "fred", it will assume
that the reader method is "getFred" and the
writer method is "setFred". Note that the
property name should start with a lower case
character, which will be capitalized in the method
names. |
| public
Class getPropertyEditorClass() |
Returns any explicit PropertyEditor
Class that has been registered for this property.
Normally this will return null,
indicating that no special editor has been
registered, so the PropertyEditorManager should be
used to locate a suitable PropertyEditor. |
| public
Class getPropertyType() |
Returns the Java type information
for the property. Note that the "Class"
object may describe a built-in Java type such as
"int". The result may be null if this is an indexed
property that does not support non-indexed access.
This is the type that will be returned by the
ReadMethod. |
| public
Method getReadMethod() |
Returns the method that should be
used to read the property value. May return null if the property can't
be read. |
| public
Method getWriteMethod() |
Returns the method that should be
used to write the property value. May return null if the property can't
be written. |
| public
boolean isBound() |
Returns whether the property is a
bound property. Updates to "bound"
properties will cause a "PropertyChange"
event to get fired when the property is changed. |
| public
boolean isConstrained() |
Returns whether the property is a
constrained property. Attempted updates to
"Constrained" properties will cause a
"VetoableChange" event to get fired when
the property is changed. |
| public
void setBound(boolean bound) |
Sets whether this property is a
bound property. |
| public
void setConstrained(boolean constrained) |
Sets whether this property is a
constrained property. |
| public
void setPropertyEditorClass(Class
propertyEditorClass) |
Sets the PropertyEditor for the
property.
Normally PropertyEditors will be found using the
PropertyEditorManager. However, if for some reason
you want to associate a particular PropertyEditor
with a given property, then you can do it with this
method. |
The IndexedPropertyDescriptor
Class
An IndexedPropertyDescriptor,
subclass of PropertyDescriptor,
describes a property that acts like an array and has an
indexed read and/or indexed write method to access specific
elements of the array. An indexed property may also provide
simple non-indexed read and write methods. If these are
present, they read and write arrays of the type returned by
the indexed read method.
IndexedPropertyDescriptor
contains the following methods, in addition to those present
in PropertyDescriptor:
| Method |
Description |
public
IndexedPropertyDescriptor(
String propertyName,
Method getter, Method setter,
Method indexedGetter, Method indexedSetter)
throws IntrospectionException |
Constructs an IndexedPropertyDescriptor,
using the name of a simple property, and Method
objects for reading and writing the property. |
public
IndexedPropertyDescriptor(
String propertyName, Class beanClass,
String getterName, String setterName, String
indexedGetterName, String indexedSetterName)
throws IntrospectionException |
Constructs an IndexedPropertyDescriptor,
using the name of a simple property, and method names
for reading and writing the property, both indexed
and non-indexed. |
public
IndexedPropertyDescriptor(
String propertyName, Class beanClass)
throws IntrospectionException |
Constructs an IndexedPropertyDescriptor
for a property that follows the standard Java
conventions by having getFoo
and setFoo accessor
methods, for both indexed access and array access.
Thus if the argument name is "fred", it will assume
that there is an indexed reader method "getFred", a
non-indexed (array) reader method also called "getFred", an indexed
writer method "setFred",
and finally a non-indexed writer method "setFred". |
| public
Class getIndexedPropertyType() |
Returns the Java Class for the
indexed properties type. Note that the Class may
describe a primitive Java type such as int.
This is the type that will be returned by the indexedReadMethod. |
| public
Method getIndexedReadMethod() |
Returns the method that should be
used to read an indexed property value. May return null if the property isn't
indexed or is write-only. |
| public
Method getIndexedWriteMethod() |
Returns the method that should be
used to write an indexed property value. May return null if the property isn't
indexed or is read-only. |
The MethodDescriptor Class
A MethodDescriptor,
a subclass of FeatureDescriptor,
describes a particular method that a Bean supports for
external access from other components.
Normally, Bean methods are exposed by making them public.
The use of a method descriptor allows you to define
explicitly which methods are available to be called for the
Bean. It also allows you to provide more descriptive
information than can be provided by low-level reflection.
MethodDescriptor
contains the following methods, in addition to those present
in FeatureDescriptor:
| Method |
Description |
| public
MethodDescriptor(Method method, ParameterDescriptor[]
parameterDescriptors) |
Constructs a MethodDescriptor from
the low-level method information and descriptive
information for each of the method's parameters |
| public
MethodDescriptor(Method method) |
Constructs a MethodDescriptor from
the low-level method information. |
| public
Method getMethod() |
Returns the low-level description of
the method |
| public
ParameterDescriptor[] getParameterDescriptors() |
Returns the locale-independent names
of the parameters. May return a null array if the parameter
names aren't known. |
The EventSetDescriptor Class
An EventSetDescriptor,
a subclass of FeatureDescriptor,
describes a group of events that a given Java bean fires. The
given group of events are all delivered as method calls on a
single event listener interface, and an event listener object
can be registered via a call on a registration method
supplied by the event source.
EventSetDescriptor
contains the following methods, in addition to those present
in FeatureDescriptor:
| Method |
Description |
public
EventSetDescriptor(
String eventSetName, Class listenerType, Method[]
listenerMethods, Method addListenerMethod, Method
removeListenerMethod)
throws IntrospectionException |
Constructs an EventSetDescriptor from
scratch using java.lang.reflect.Method and
java.lang.Class objects.
|
public
EventSetDescriptor(
String eventSetName, Class listenerType,
MethodDescriptor[] listenerMethodDescriptors, Method
addListenerMethod, Method removeListenerMethod)
throws IntrospectionException |
Constructs an EventSetDescriptor from
scratch using java.lang.reflect.MethodDescriptor and
java.lang.Class objects.
|
public
EventSetDescriptor(
Class sourceClass, String eventSetName, Class
listenerType, String listenerMethodName)
throws IntrospectionException |
Constructs an EventSetDescriptor assuming
that you are following the most simple standard
design pattern, where a named event "fred"
is (1) delivered as a call on the single method of
interface FredListener, (2) has a single argument of
type FredEvent, and (3) where the FredListener may be
registered with a call on an addFredListener method
of the source component and removed with a call on a
removeFredListener method. |
public
EventSetDescriptor(
Class sourceClass, String eventSetName, Class
listenerType, String[] listenerMethodNames, String
addListenerMethodName, String
removeListenerMethodName)
throws IntrospectionException |
Constructs an EventSetDescriptor from
scratch using string names. |
| public
Method getAddListenerMethod() |
Returns the method used to register
a listener at the event source. |
| public
MethodDescriptor[] getListenerMethodDescriptors() |
Returns an array of MethodDescriptor
objects for the target methods within the target
listener interface that will get called when events
are fired. |
| public
Method[] getListenerMethods() |
Returns an array of Method objects
for the target methods within the target listener
interface that will get called when events are fired. |
| public
Class getListenerType() |
Returns the Class object for the
target interface that will get invoked when the event
is fired. |
| public
Method getRemoveListenerMethod() |
Returns the method used to register
a listener at the event source.
|
| public
boolean isInDefaultEventSet() |
Reports whether an event set is in
the "default set". |
| public
boolean isUnicast() |
Reports whether the set is unicast.
Defaults to "false".
Normally event sources are multicast. However there
are some exceptions that are strictly unicast. |
| public
void setInDefaultEventSet(boolean inDefaultEventSet) |
Marks an event set as being in the
"default" set (or not). By default this is
true. |
| public
void setUnicast(boolean unicast) |
Marks an event set as unicast (or
not). |
|