Online Training Index
101, Part III:
Writing a Simple JavaBean
by Beth Stearns
January 2001
Introduction |
Page 1 |
Page 2 |
Page 3 |
Page 4
Customizing Beans for Builder Tools
The BeanBox and other application construction tools can uncover information specified about a Bean using the BeanInfo class. This class makes it possible to hook up Bean components through a visual programming paradigm. Using the BeanInfo class enables you to control how your Bean is presented to programmers inside these application builders. For example, you can make Beans automatically adjust their size to accommodate changes in their content.
By adding a special BeanInfo class, you can change the name used to display the Bean, and you can control the visibility of properties and methods to builder tools. You might want to control a Bean's property visibility to give a Bean a clean presentation to users. You may also want to provide special editors or configuration wizards to allow users to customize your Beans. In this part of the tutorial, you will learn how to add a PropertyEditor to a Bean and how to use method descriptors and property descriptors to customize the Bean's presentation.
Resizing Beans
In this section, you will learn how to set the preferred and minimium sizes for a Bean displayed in a builder tool. You can also make Beans automatically adjust their size to accomodate changes in their content.
Adding a BeanInfo Class to a Bean
Adding a BeanInfo class for NervousText lets you specify a custom presentation for the Bean. You can change the name displayed by builder tools as well as specify icons to be used to show the Bean in a builder tool's palette. A BeanInfo object also lets you specify property descriptors that determine what properties are publicly visible. This is handy for presenting a cleaner list of customizable properties for programmers to manipulate.
Adding a PropertyEditor to a Bean
Adding a PropertyEditor to your Bean lets you have complete control over how properties are modified by end users. You can provide anything from simple choice lists to complex configuration wizards that are programs in their own right. This section shows you how to add a PropertyEditor to NervousText.
Reflection and Method Descriptors
This section shows how to use reflection to create method objects for building MethodDescriptors used by Beans. A list of such descriptors can be associated with a Bean through a BeanInfo class to present a reduced interface that is less cluttered and easier to read. Specifying a list of method descriptors is similar to specifying a list of property descriptors to reduce the number of visible properties.
Resizing Beans
This part of the tutorial makes minor modifications to the NervousText bean so that it is more user friendly. You will also add a BeanInfo class and a PropertyEditor class to control customizing the Bean inside a builder tool.
The BeanInfo class allows the BeanBox to uncover information you specify about the Bean. By using a BeanInfo class with your Bean, you override the information that the BeanBox's default introspection mechanism discovers and presents to programmers from within an application builder tool.
You may have noticed that if you type a long label name in the property editor for NervousText, the right part of the text gets truncated. We are going to fix this by adding a sizeToFit method to the Bean. We will call the method from the setText
property setter, which is called every time a change is made to the label.
Step 1. Create the source file
In this example you work on NervousText05.java.
- Copy
NervousText04.java to NervousText05.java
- Make the appropriate name changes. That is, change
NervousText04 to NervousText05 throughout the file.
- Do a global search and replace because some of the diagnostic strings print the class name to
stdout.
Step 2. Make the Bean automatically resizeable
- Add the code for the
sizeToFit method. Add the following code to NervousText05.java:
private void sizeToFit() {
Dimension d = getPreferredSize();
setSize(d.width, d.height);
Component p = getParent();
if (p != null) {
p.invalidate();
p.doLayout();
}
} |
- Add the call to the
sizeToFit method in setText. Add the line:
sizeToFit();
immediately after the call to getChaos.
The setText method should now look like this:
public void setText(String newstring){
String oldstring = s;
s=new String(newstring);
separated= new char[s.length()];
s.getChars(0,s.length(),separated,0);
sizeToFit();
support.firePropertyChange(
"text", oldstring, newstring);
} |
- Either comment out or delete the old definition of
preferredSize. (Comment it out as we do here if you want to revert back to the old definition later.)
/* Try dynamic sizing
// public Dimension preferredSize() {
// use this for a fixed size bean
public Dimension getMinimumSize() {
// use this for a variable size bean
return (new Dimension(150,150));
}
*/ |
- Rewrite the sizeToFit method
The BeanBox calls the preferredSize method to decide how large the Bean should be when displayed.
private void sizeToFit() {
Dimension d = getPreferredSize();
setSize(d.width, d.height);
Component p = getParent();
if (p != null) {
p.invalidate();
p.doLayout();
}
} |
Step 3. Compile the program
- Compile the program as follows:
javac -d . NervousText 05.java
Remember to include the
-d .
argument; otherwise the class file is created in the wrong directory.
Step 4. Build and install the JAR
You can now make a JAR file from the Bean and place the JAR file in the directory where the
BeanBox expects to find JAR files.
- Create the minifest file
Name: sun/beanbox/beans/NervousText05.class
Java-Bean: True
There's a makefile to make the manifest for you if you don't want to do it by hand. It will also build the JAR file and copy it to the right location, provided that you have set the target directories at the top of the file. Remember to substitute the path to your directories for JDK_HOME and BDK_HOME:
JDK_HOME=/home_gvoss/work97/06/jdk1.1.2/jdk1.1.2
JDK_BIN=$(JDK_HOME)/bin
BDK_HOME=/home_gvoss/work97/06/bdk
JAR_DIR=$(BDK_HOME)/beans/jars
Step 5. Test the Bean in the BeanBox
- Run the BeanBox and drop a
NervousText05 Bean on the form.
What happens when you use the property editor to type in a string larger than will fit in the original box surrounding the Bean?
Look at NervousText05.java to see the final form of the code.
Adding a BeanInfo Class to a Bean
In this section you add a BeanInfo class and associate that class with NervousText. Most of the work is in the BeanInfo class; you will make minimal changes to the actual NervousText Bean. The BeanInfo class name will be NervousText 06BeanInfo, and you will also change NervousText05 to NervousText06.
Step 1. Create the source file
- Copy
NervousText05.java to NervousText06.java and make the appropriate name changes.
- Change
NervousText05 to NervousText06 throughout the file. Be sure to change the diagnostic strings that print the class name to stdout.
Step 2. Consider your Bean's name
Suppose your marketing department wants to put the right spin on the name for NervousText when viewed by the public from inside builder tools. The name of this Bean might make programmers a little uneasy. Instead of the class name NervousText06 appearing as the Bean name inside of builder tools, the marketing folks would like to display the string Uneasy Text.
Such name changes are typical of the way Beans evolve. When you go to sell a Bean that you've built, it may not be convenient to change its class names. Also, you have more flexibility using arbitrary strings to describe the Bean than the syntax allowed for Java class names.
Step 3. Create the NervousText 06BeanInfo class
Step 4. Define a getBeanDescriptor method
- Write the getBean Discriptor
Here's an example of a
getBeanDescriptor
method definition:
public BeanDescriptor getBeanDescriptor() {
BeanDescriptor bd;
...
return bd;
}
- You also need to call a method defined in
BeanDescriptor called getBeanDescriptor. Create an instance of a BeanDescriptor associated with your NervousText 06 Bean:
BeanDescriptor bd =
new BeanDescriptor(beanClass);
The argument to the BeanDescriptor
constructor is the Class object for your Bean. JDK 1.1 introspection allows you to get the
Class
object associated with a class such as
MyClass
using the construct:
MyClass.class
Our example declares the Bean class as a static constant inside the
NervousText06BeanInfo
class:
private final static Class beanClass =
NervousText 06.class;
- Once you have the Bean descriptor, you call
setDisplayName to set the Bean's name used by builder tools. Pass the method the desired name as a String argument.
bd.setDisplayName("Uneasy Text");
The getBeanDescriptor method in your BeanInfo class must return the BeanDescriptor object so that it can be created and used from within the builder tool.
If you like, you can include some println statements to help with debugging. This is a good way to ensure that the builder tool actually calls the method.
public BeanDescriptor getBeanDescriptor() {
System.err.println("ENTER-->
NervousText 06BeanInfo.getBeanDescriptor");
...
System.err.println("EXIT---->
NervousText 06BeanInfo.getBeanDescriptor");
...
} |
Your getBeanDescriptor method now looks like this:
public BeanDescriptor getBeanDescriptor() {
System.err.println("ENTER--->
NervousText 06BeanInfo.getBeanDescriptor");
BeanDescriptor bd = new BeanDescriptor(beanClass);
bd.setDisplayName("Uneasy Text");
System.err.println("EXIT---->
NervousText 06BeanInfo.getBeanDescriptor");
return bd;
} |
Step 5. Define a getPropertyDescriptors method
You might also want to limit the number of properties displayed in the property sheet. This is very likely if your Bean is a subclass of one of the AWT components, which can define many more properties than you want a programmer to see. Use the getPropertyDescriptors method to limit the properties displayed in the property sheet.
- Start with the method skeleton including the exception handling code:
public PropertyDescriptor[] getPropertyDescriptors() {
try {
...
} catch (IntrospectionException e) {
throw new Error(e.toString());
}
} |
- Next, declare an instance of a
PropertyDescriptor
inside the try block.
PropertyDescriptor textPD =
new PropertyDescriptor("text", beanClass);
The method returns an array of property descriptors. The array contains all the properties
you want to be visible to the builder tool. In our example, only one property will be visiblethe text property
controlling the label for NervousText.
- Create the array of property descriptors and add the text property descriptor to it:
PropertyDescriptor rv[] = {textPD};
...
Notice that an initializer is used to declare a constant array of one element, textPD.
- Return the array to the builder tool.
...
return rv;
You now have the following
getPropertyDescriptors
method definition within
NervousText06BeanInfo.
public PropertyDescriptor[]
getPropertyDescriptors() {
try {
PropertyDescriptor textPD =
new PropertyDescriptor("text", beanClass);
PropertyDescriptor rv[] = {textPD};
return rv;
} catch (IntrospectionException e) {
throw new Error(e.toString());
}
} |
The complete source code for NervousText06BeanInfo.java looks as follows:
package sun.beanbox.beans;
import java.beans.*;
public class NervousText 06BeanInfo
extends SimpleBeanInfo {
private final static Class beanClass =
NervousText 06.class;
public BeanDescriptor getBeanDescriptor() {
System.err.println("ENTER--->
NervousText 06BeanInfo.getBeanDescriptor");
BeanDescriptor bd = new BeanDescriptor(beanClass);
bd.setDisplayName("Uneasy Text");
System.err.println("EXIT---->
NervousText 06BeanInfo.getBeanDescriptor");
return bd;
}
public PropertyDescriptor[] getPropertyDescriptors() {
try {
PropertyDescriptor textPD =
new PropertyDescriptor("text", beanClass);
PropertyDescriptor rv[] = {textPD};
return rv;
} catch (IntrospectionException e) {
throw new Error(e.toString());
}
}
} |
Step 6. Compile the programs
Step 7. Build and install the JAR file
- Add both classes that you just compiled to add to your JAR file. One class is a Bean, but the other is a regular Java class. However, you need only one manifest file and one JAR file. Create the manifest file in a text editor.
Name: sun/beanbox/beans/NervousText06.class
Java-Bean: True
Name: sun/beanbox/beans/NervousText06BeanInfo.class
A makefile will create the manifest for you if you don't want to do it by hand. It also builds the JAR file and copies it to the right location, provided that you have set the target directories at the top of the file.
- Create the JAR file and copy it to the
jars directory, as follows:
jar cfm NervousText 06.jar manifest.tmp \
sun/beanbox/beans/NervousText06.class \
sun/beanbox/beans/NervousText06BeanInfo.class
cp -p NervousText 06.jar BDK_HOME/beans/jars
- Substitute your BDK installation directory for
BDK_HOME when you copy the JAR.
Step 8. Test the bean in the BeanBox
- Run the BeanBox and drop a
NervousText06 Bean on the form.
Notice that the name for the bean is now "Uneasy Text." The marketing department is happy. Also, look at the
property and see how it differs from the previous example. There should now be only one field that appears in the
property sheet, the text property for NervousText06.
Look at the example code for
NervousText06.java
and NervousText06BeanInfo.java
to see these classes in their final forms.
Adding a PropertyEditor to a Bean
This section adds a PropertyEditor class and associates it with your NervousText Bean. The only work you have to do is to define this PropertyEditor class, which we call
NervousText07TextPropertyEditor. You must also create the NervousText07 and
NervousText07BeanInfo classes, but you can copy and modify these classes from the NervousText06 and NervousText06BeanInfo
versions.
Here's the full listing of the
NervousText07TextPropertyEditor.java
source file:
package sun.beanbox.beans;
import java.beans.*;
public class NervousText 07TextPropertyEditor
extends PropertyEditorSupport {
public String[] getTags() {
String values[] = {
"Nervous Text",
"Anxious Text",
"Funny Text",
"Wobbly Text"};
return values;
}
} |
Step 1. Create the NervousText07 and NervousText07BeanInfo classes
- Copy the
NervousText06.java and NervousText06BeanInfo.java source files to
NervousText07.java and NervousText07BeanInfo.java,
respectively.
- Change all occurrences of
NervousText06 to NervousText07.
- Two minor changes are required for
NervousText07BeanInfo.java.
For clarity, change the name of the Bean in the property descriptor to distinguish it from
NervousText06BeanInfo.java.
- Change:
bd.setDisplayName("Uneasy Text");
to
bd.setDisplayName("Uneasy Text 07");
The second change attaches the property editor you're about to create to instances of the
BeanInfo class associated with your Bean. You will see how to do this after you create
NervousText07TextPropertyEditor.
Step 2. Create NervousText07TextPropertyEditor
Step 3. Set the PropertyEditor in the text property's PropertyDescriptor
Since you've created the property editor, you're ready to attach it to the instances of the NervousText07BeanInfo class associated with your Bean.
Step 4. Compile the programs
Step 5. Build and install the JAR file
- Create the manifest file by using a text editor to enter the text below into a file called
manifest.tmp.
The manifest file should look like this:
Name: sun/beanbox/beans/NervousText07.class
Java-Bean: True
Name: sun/beanbox/beans/NervousText07BeanInfo.class
Name: sun/beanbox/beans/NervousText07TextPropertyEditor.class
Note that there are three classes in the JAR file, but only one is a Bean.
- Create the JAR file and copy it to the
jars directory, as follows:
jar cfm NervousText 07.jar manifest.tmp \
sun/beanbox/beans/NervousText07.class \
sun/beanbox/beans/NervousText07BeanInfo.class \
sun/beanbox/beans/NervousText07TextPropertyEditor.class
cp -p NervousText 07.jar BDK_HOME/beans/jars
Be sure to substitute your BDK installation directory for BDK_HOME in the above commands.
There's a makefile that builds the JAR file and puts it in the correct location for you, if you prefer.
Step 6. Test the Bean in the BeanBox
When you test the Bean in the BeanBox, notice that its property editor has a drop-down choice box instead of a editable text field. The choice box contains the array of strings that appeared in the getTags method of NervousText07TextPropertyEditor.
For the final versions of the examples in this section, see:
NervousText07.java
NervousText07BeanInfo.java
NervousText07TextPropertyEditor.java
Reflection and Method Descriptors
You can use method descriptors to limit the methods exposed to builder tools. This part of the tutorial uses the property editor and NervousText07 classes from the previous lessons. It makes changes only to the NervousText's BeanInfo class, and these changes result in a cleaner interface because they reduce the number of methods exposed to builder tools.
Step 1.
- Create
NervousText08 files from the NervousText07 files.
- Copy
NervousText07.java
to NervousText08.java, then copy NervousText07BeanInfo.java to NervousText08BeanInfo.java.
- Copy
NervousText07TextPropertyEditor.java to NervousText08TextPropertyEditor.java.
- Make the appropriate changes to the class names and debug message stubs in each filethat is, change
NervousText07 to NervousText08 throughout each file.
Step 2. Add the import statement for the Method class to NervousText08
To use the Method class, you need to add an import statement at the top of the file.
import java.lang.reflect.Method;
Step 3. Change the Bean name as it appears in the builder tools
Change the name displayed by the Bean as it appears from within builder tools. In the NervousText08BeanInfo.java file, change the getBeanDescriptor
method to display 08 instead of 07.
Step 4: Reduce the number of exposed methods
The next set of changes reduces the number of event handler methods that a builder tool can discover. Your Bean might have a dozen or more public methods, but you only want two of the methods to be exposed. These changes limit the displayed methods to one ActionEvent event handler to respond to button presses from other objects and one PropertyChangeEvent event handler. Recall the PropertyChangeEvent event supports bound properties so that interested listeners are notified of changes to the text.
- To reduce the visible methods, add a new method called
getMethodDescriptors whose structure resembles getPropertyDescriptors.
Instead of returning an array of PropertyDescriptor,
getMethodDescriptors returns an array of MethodDescriptor
objects. The basic skeleton of this method is as follows:
public MethodDescriptor[] getMethodDescriptors() {
...
MethodDescriptor result[] = { ... };
...
return result;
}
- Setting up the array of returned
MethodDescriptor objects is a bit involved. You want to return four
methods: three methods which respond to ActionEvents from buttonsa startMethod,
a stopMethod, and a changeDirectionMethodand a method to respond to property change
notifications from other Beans
propertyChangeMethod. Declare each array as a local variable inside of getMethodDescriptors:
public MethodDescriptor[] getMethodDescriptors() {
Method startMethod, stopMethod, changeDirectionMethod;
Method propertyChangeMethod;
...
}
Step 5: Call the getMethod method for the Bean methods
- Call
getMethod for the Class object that is automatically associated with NervousText08. Recall that this Class object can be retrieved by direct reference, so the call to getMethod has the form:
NervousText08.class.getMethod( ... );
This call requires two arguments. The first is a String naming the method. The second is an array of objects that are the Classes of the arguments required by the method you are looking up. In other words, the arguments to getMethod represent the signature of the method you want to reference.
Because the start and stop methods do not take any arguments, the array of arguments passed to getMethod is empty.
Class args[] = { };
- Once you've declared the argument array, you can retrieve references to the first three methods:
try {
startMethod = NervousText 08.class.getMethod("start",
args);
stopMethod = NervousText 08.class.getMethod("stop",
args);
The changeDirection method in NervousText08 takes an ActionEvent
as an argument. The second argument to NervousText08.class.getMethod for changeDirection
must therefore be an array of one element. Declare the array as follows:
Class actionEventArgs[] = { java.awt.event.ActionEvent.class };
- With the array declared you can retrieve the
changeDirection method:
changeDirectionMethod =
NervousText08.class.getMethod("changeDirection",
actionEventArgs);
- Set up the
PropertyChangeEvent similarly:
Class propertyChangeEventArgs[] = { PropertyChangeEvent.class };
...
propertyChangeMethod = NervousText 08.class.getMethod(
"makeChange", propertyChangeEventArgs);
Step 6: Build an array of MethodDescriptor objects
Step 7: Compile the Bean and create the JAR file
- Compile the Bean, create a manifest file for it and its associated classes, and then create the JAR file. The steps for this are the same as in the previous section.
Step 8: Test the Bean in the BeanBox
- Place
NervousText08Bean in the BeanBox and try to hook up action events from buttons or property change events. Notice that the hookup dialog only displays the four methods named in the
MethodDescriptor array.
Where to Get More Information
Now that you've finished the JavaBeans tutorial, you're ready to put into practice what you've learned and increase your JavaBean programming skills. You can find out more information about JavaBeans by visiting Sun's JavaBean web site. There you will find pointers to the full set of JavaBeans documentation, including the latest specification, plus additional tutorials and recommended third-party books. There are also links to an online FAQ, training and support assistance, and suggestions for marketing your JavaBeans.

Introduction | Page
2 | Page 3 | Page 4
|