SHARE
Facebook X Pinterest WhatsApp

Visual programming and Beans

Bruce Eckel’s Thinking in Java Contents | Prev | Next and Beans So far in this book you’ve seen how valuable Java is for creating reusable pieces of code. The “most reusable” unit of code has been the class, since it comprises a cohesive unit of characteristics (fields) and behaviors (methods) that can be reused […]

Written By
thumbnail
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

and
Beans

So


far in this book you’ve seen how valuable

Java
is for creating
reusable
pieces of code. The “most reusable” unit of code has been the
class, since it comprises a cohesive unit of characteristics (fields) and
behaviors (methods) that can be reused either directly via composition or
through inheritance.

Inheritance


and polymorphism are essential parts of object-oriented programming, but in the


majority of cases when you’re putting together an application, what you


really want is components that do exactly what you need. You’d like to


drop these parts into your design like the electronic engineer puts together


chips on a circuit board (or even, in the case of Java, onto a Web page). It


seems, too, that there should be some way to accelerate this “modular


assembly” style of programming.

Visual
programming” first became successful –
very
successful – with
Microsoft’s
Visual Basic (VB), followed by a second-generation design in
Borland’s
Delphi (the primary inspiration for the Java Beans design). With these
programming tools the components are represented visually, which makes sense
since they usually display some kind of visual component such as a button or a
text field. The visual representation, in fact, is often exactly the way the
component will look in the running program. So part of the process of visual
programming involves dragging a component from a pallet and dropping it onto
your form. The
application
builder tool writes code as you do this, and that code will cause the component
to be created in the running program.

Simply


dropping the component onto a form is usually not enough to complete the


program. Often, you must change the characteristics of a component, such as


what color it is, what text is on it, what database it’s connected to,


etc. Characteristics that can be modified at design time are referred to as

properties.
You can manipulate the properties of your component inside the application
builder tool, and when you create the program this configuration data is saved
so that it can be rejuvenated when the program is started.

By


now you’re probably used to the idea that an object is more than


characteristics; it’s also a set of behaviors. At design-time, the


behaviors of a visual component are partially represented by

events,
meaning “Here’s something that can happen to the component.”
Ordinarily, you decide what you want to happen when an event occurs by tying
code to that event.

Here’s


the critical part: the application builder tool is able to dynamically


interrogate (using

reflection)
the component to find out which properties and events the component supports.
Once it knows what they are, it can display the properties and allow you to
change those (saving the state when you build the program), and also display
the events. In general, you do something like double clicking on an event and
the application builder tool creates a code body and ties it to that particular
event. All you have to do at that point is write the code that executes when
the event occurs.

All


this adds up to a lot of work that’s done for you by the application


builder tool. As a result you can focus on what the program looks like and what


it is supposed to do, and rely on the application builder tool to manage the


connection details for you. The reason that visual programming tools have been


so successful is that they dramatically speed up the process of building an


application – certainly the user interface, but often other portions of


the application as well.


What
is a Bean?

After


the dust settles, then, a

component
is really just a block of code, typically embodied in a class. The key issue is
the ability for the application builder tool to discover the properties and
events for that component. To create a VB component, the programmer had to
write a fairly complicated piece of code following certain conventions to
expose the properties and events. Delphi was a second-generation visual
programming tool and the language was actively designed around visual
programming so it is much easier to create a visual component. However, Java
has brought the creation of visual components to its most advanced state with
Java Beans, because a Bean is just a class. You don’t have to write any
extra code or use special language extensions in order to make something a
Bean. The only thing you need to do, in fact, is slightly modify the way that
you name your methods. It is the method name that tells the application builder
tool whether this is a property, an event, or just an ordinary method.

In


the Java documentation, this naming convention is mistakenly termed a


“design pattern.” This is unfortunate since design patterns (see


Chapter 16) are challenging enough without this sort of confusion. It’s


not a design pattern, it’s just a

naming
convention and it’s fairly simple:
  1. For
    a property named
    xxx,
    you typically create two methods:
    getXxx( )
    and
    setXxx( ).
    Note that the first letter after get or set is automatically lowercased to
    produce the property name. The type produced by the “get” method is
    the same as the type of the argument to the “set” method. The name
    of the property and the type for the “get” and “set”
    are not related.
  2. For
    a boolean property, you can use the “get” and “set”
    approach above, but you can also use “is” instead of
    “get.”
  3. Ordinary
    methods of the Bean don’t conform to the above naming convention, but
    they’re
    public.
  4. For
    events, you use the “listener” approach. It’s exactly the
    same as you’ve been seeing:
    addFooBarListener(FooBarListener)
    and
    removeFooBarListener(FooBarListener)
    to handle a
    FooBarEvent.
    Most of the time the built-in events and listeners will satisfy your needs, but
    you can also create your own events and listener interfaces.

Point


1 above answers a question about something you might have noticed in the change


from Java 1.0


to Java 1.1
:
a number of method names have had small, apparently meaningless name changes.
Now you can see that most of those changes had to do with adapting to the
“get” and “set” naming conventions in order to make
that particular component into a Bean.

We


can use these guidelines to create a simple Bean:

//: Frog.java
// A trivial Java Bean
package frogbean;
import java.awt.*;
import java.awt.event.*;
 
class Spots {}
 
public class Frog {
  private int jumps;
  private Color color;
  private Spots spots;
  private boolean jmpr;
  public int getJumps() { return jumps; }
  public void setJumps(int newJumps) {
    jumps = newJumps;
  }
  public Color getColor() { return color; }
  public void setColor(Color newColor) {
    color = newColor;
  }
  public Spots getSpots() { return spots; }
  public void setSpots(Spots newSpots) {
    spots = newSpots;
  }
  public boolean isJumper() { return jmpr; }
  public void setJumper(boolean j) { jmpr = j; }
  public void addActionListener(
      ActionListener l) {
    //...
  }
  public void removeActionListener(
      ActionListener l) {
    // ...
  }
  public void addKeyListener(KeyListener l) {
    // ...
  }
  public void removeKeyListener(KeyListener l) {
    // ...
  }
  // An "ordinary" public method:
  public void croak() {
    System.out.println("Ribbet!");
  }
} ///:~ 

First,


you can see that it’s just a class. Usually, all your fields will be


private

,


and accessible only through methods. Following the naming convention, the


properties are


jumps

,


color

,


spots

,


and


jumper

(notice the change in case of the first letter in the property name). Although


the name of the internal identifier is the same as the name of the property in


the first three cases, in


jumper

you can see that the property name does not force you to use any particular


name for internal variables (or, indeed, to even


have

any internal variable for that property).

The


events this Bean handles are


ActionEvent

and


KeyEvent

,


based on the naming of the “add” and “remove” methods


for the associated listener. Finally, you can see that the ordinary method


croak( )

is still part of the Bean simply because it’s a


public

method, not because it conforms to any naming scheme.


Extracting
BeanInfo

with
the Introspector

One


of the most critical parts of the Bean scheme occurs when you drag a Bean off a


palette and plop it down on a form. The application builder tool must be able


to create the Bean (which it can do if there’s a default constructor) and


then, without access to the Bean’s source code, extract all the necessary


information to create the property sheet and event handlers.

Part


of the solution is already evident from the end of Chapter 11: Java 1.1


reflection
allows all the methods of an anonymous class to be discovered. This is perfect
for solving the Bean problem without requiring you to use any extra language
keywords like those required in other visual programming languages. In fact,
one of the prime reasons that reflection was added to Java 1.1 was to support
Beans (although reflection also supports object serialization and remote method
invocation). So you might expect that the creator of the application builder
tool would have to reflect each Bean and hunt through its methods to find the
properties and events for that Bean.

This


is certainly possible, but the Java designers wanted to provide a standard


interface for everyone to use, not only to make Beans simpler to use but also


to provide a standard gateway to the creation of more complex Beans. This


interface is the

Introspector
class, and the most important method in this class is the
static
getBeanInfo( ).
You pass a
Class
handle to this method and it fully interrogates that class and returns a
BeanInfo
object that you can then dissect to find properties, methods, and events.

Usually


you won’t care about any of this – you’ll probably get most


of your Beans off the shelf from vendors, and you don’t need to know all


the magic that’s going on underneath. You’ll simply drag your Beans


onto your form, then configure their properties and write handlers for the


events you’re interested in. However, it’s an interesting and


educational exercise to use the


Introspector

to display information about a Bean, so here’s a tool that does it


(you’ll find it in the


frogbean

subdirectory):

//: BeanDumper.java
// A method to introspect a Bean
import java.beans.*;
import java.lang.reflect.*;
 
public class BeanDumper {
  public static void dump(Class bean){
    BeanInfo bi = null;
    try {
      bi = Introspector.getBeanInfo(
        bean, java.lang.Object.class);
    } catch(IntrospectionException ex) {
      System.out.println("Couldn't introspect " +
        bean.getName());
      System.exit(1);
    }
    PropertyDescriptor[] properties =
      bi.getPropertyDescriptors();
    for(int i = 0; i < properties.length; i++) {
      Class p = properties[i].getPropertyType();
      System.out.println(
        "Property type:n  " + p.getName());
      System.out.println(
        "Property name:n  " +
        properties[i].getName());
      Method readMethod =
        properties[i].getReadMethod();
      if(readMethod != null)
        System.out.println(
          "Read method:n  " +
          readMethod.toString());
      Method writeMethod =
        properties[i].getWriteMethod();
      if(writeMethod != null)
        System.out.println(
          "Write method:n  " +
          writeMethod.toString());
      System.out.println("====================");
    }
    System.out.println("Public methods:");
    MethodDescriptor[] methods =
      bi.getMethodDescriptors();
    for(int i = 0; i < methods.length; i++)
      System.out.println(
        methods[i].getMethod().toString());
    System.out.println("======================");
    System.out.println("Event support:");
    EventSetDescriptor[] events =
      bi.getEventSetDescriptors();
    for(int i = 0; i < events.length; i++) {
      System.out.println("Listener type:n  " +
        events[i].getListenerType().getName());
      Method[] lm =
        events[i].getListenerMethods();
      for(int j = 0; j < lm.length; j++)
        System.out.println(
          "Listener method:n  " +
          lm[j].getName());
      MethodDescriptor[] lmd =
        events[i].getListenerMethodDescriptors();
      for(int j = 0; j < lmd.length; j++)
        System.out.println(
          "Method descriptor:n  " +
          lmd[j].getMethod().toString());
      Method addListener =
        events[i].getAddListenerMethod();
      System.out.println(
          "Add Listener Method:n  " +
        addListener.toString());
      Method removeListener =
        events[i].getRemoveListenerMethod();
      System.out.println(
        "Remove Listener Method:n  " +
        removeListener.toString());
      System.out.println("====================");
    }
  }
  // Dump the class of your choice:
  public static void main(String[] args) {
    if(args.length < 1) {
      System.err.println("usage: n" +
        "BeanDumper fully.qualified.class");
      System.exit(0);
    }
    Class c = null;
    try {
      c = Class.forName(args[0]);
    } catch(ClassNotFoundException ex) {
      System.err.println(
        "Couldn't find " + args[0]);
      System.exit(0);
    }
    dump(c);
  }
} ///:~ 
BeanDumper.dump( )

is the method that does all the work. First it tries to create a


BeanInfo

object, and if successful calls the methods of


BeanInfo

that produce information about properties, methods, and events. In


Introspector.getBeanInfo( )

,


you’ll see there is a second argument. This tells the


Introspector

where to stop in the inheritance hierarchy. Here, it stops before it parses all


the methods from


Object

,


since we’re not interested in seeing those.

For


properties,

getPropertyDescriptors( )
returns an array of
PropertyDescriptors.
For each
PropertyDescriptor
you can call
getPropertyType( )
to find the class of object that is passed in and out via the property methods.
Then, for each property you can get its pseudonym (extracted from the method
names) with
getName( ),
the method for reading with
getReadMethod( ),
and the method for writing with
getWriteMethod( ).
These last two methods return a
Method
object that can actually be used to invoke the corresponding method on the
object (this is part of reflection).

For


the public methods (including the property methods),

getMethodDescriptors( )
returns an array of
MethodDescriptors.
For each one you can get the associated
Method
object and print out its name.

For


the events,

getEventSetDescriptors( )
returns an array of (what else?)
EventSetDescriptors.
Each of these can be queried to find out the class of the listener, the methods
of that listener class, and the add- and remove-listener methods. The
BeanDumper
program
prints out all of this information.

If


you invoke


BeanDumper

on the


Frog

class like this:

java
BeanDumper frogbean.Frog

the


output, after removing extra details that are unnecessary here, is:

class name: Frog
Property type:
  Color
Property name:
  color
Read method:
  public Color getColor()
Write method:
  public void setColor(Color)
====================
Property type:
  Spots
Property name:
  spots
Read method:
  public Spots getSpots()
Write method:
  public void setSpots(Spots)
====================
Property type:
  boolean
Property name:
  jumper
Read method:
  public boolean isJumper()
Write method:
  public void setJumper(boolean)
====================
Property type:
  int
Property name:
  jumps
Read method:
  public int getJumps()
Write method:
  public void setJumps(int)
====================
Public methods:
public void setJumps(int)
public void croak()
public void removeActionListener(ActionListener)
public void addActionListener(ActionListener)
public int getJumps()
public void setColor(Color)
public void setSpots(Spots)
public void setJumper(boolean)
public boolean isJumper()
public void addKeyListener(KeyListener)
public Color getColor()
public void removeKeyListener(KeyListener)
public Spots getSpots()
======================
Event support:
Listener type:
  KeyListener
Listener method:
  keyTyped
Listener method:
  keyPressed
Listener method:
  keyReleased
Method descriptor:
  public void keyTyped(KeyEvent)
Method descriptor:
  public void keyPressed(KeyEvent)
Method descriptor:
  public void keyReleased(KeyEvent)
Add Listener Method:
  public void addKeyListener(KeyListener)
Remove Listener Method:
  public void removeKeyListener(KeyListener)
====================
Listener type:
  ActionListener
Listener method:
  actionPerformed
Method descriptor:
  public void actionPerformed(ActionEvent)
Add Listener Method:
  public void addActionListener(ActionListener)
Remove Listener Method:
  public void removeActionListener(ActionListener)
====================

This


reveals most of what the


Introspector

sees as it produces a


BeanInfo

object from your Bean. You can see that the type of the property and its name


are independent. Notice the lowercasing of the property name. (The only time


this doesn’t occur is when the property name begins with more than one


capital letter in a row.) And remember that the method names you’re


seeing here (such as the read and write methods) are actually produced from a


Method

object that can be used to invoke the associated method on the object.

The


public method list includes the methods that are not associated with a property


or event, such as


croak( )

,


as well as those that are. These are all the methods that you can call


programmatically for a Bean, and the application builder tool can choose to


list all of these while you’re making method calls, to ease your task.

Finally,


you can see that the events are fully parsed out into the listener, its


methods, and the add- and remove-listener methods. Basically, once you have the


BeanInfo

,


you can find out everything of importance for the Bean. You can also call the


methods for that Bean, even though you don’t have any other information


except the object (again, a feature of reflection).


A
more sophisticated Bean

This


next example is slightly more sophisticated, albeit frivolous. It’s a


canvas that draws a little circle around the mouse whenever the mouse is moved.


When you press the mouse, the word “Bang!” appears in the middle of


the screen, and an action listener is fired.

The


properties you can change are the size of the circle as well as the color,


size, and text of the word that is displayed when you press the mouse. A


BangBean

also has its own

addActionListener( )
and
removeActionListener( )
so you can attach your own listener that will be fired when the user clicks on
the
BangBean.
You should be able to recognize the property and event support:
//: BangBean.java
// A graphical Bean
package bangbean;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
 
public class BangBean extends Canvas
     implements Serializable {
  protected int xm, ym;
  protected int cSize = 20; // Circle size
  protected String text = "Bang!";
  protected int fontSize = 48;
  protected Color tColor = Color.red;
  protected ActionListener actionListener;
  public BangBean() {
    addMouseListener(new ML());
    addMouseMotionListener(new MML());
  }
  public int getCircleSize() { return cSize; }
  public void setCircleSize(int newSize) {
    cSize = newSize;
  }
  public String getBangText() { return text; }
  public void setBangText(String newText) {
    text = newText;
  }
  public int getFontSize() { return fontSize; }
  public void setFontSize(int newSize) {
    fontSize = newSize;
  }
  public Color getTextColor() { return tColor; }
  public void setTextColor(Color newColor) {
    tColor = newColor;
  }
  public void paint(Graphics g) {
    g.setColor(Color.black);
    g.drawOval(xm - cSize/2, ym - cSize/2,
      cSize, cSize);
  }
  // This is a unicast listener, which is
  // the simplest form of listener management:
  public void addActionListener (
      ActionListener l)
        throws TooManyListenersException {
    if(actionListener != null)
      throw new TooManyListenersException();
    actionListener = l;
  }
  public void removeActionListener(
      ActionListener l) {
    actionListener = null;
  }
  class ML extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
      Graphics g = getGraphics();
      g.setColor(tColor);
      g.setFont(
        new Font(
          "TimesRoman", Font.BOLD, fontSize));
      int width =
        g.getFontMetrics().stringWidth(text);
      g.drawString(text,
        (getSize().width - width) /2,
        getSize().height/2);
      g.dispose();
      // Call the listener's method:
      if(actionListener != null)
        actionListener.actionPerformed(
          new ActionEvent(BangBean.this,
            ActionEvent.ACTION_PERFORMED, null));
    }
  }
  class MML extends MouseMotionAdapter {
    public void mouseMoved(MouseEvent e) {
      xm = e.getX();
      ym = e.getY();
      repaint();
    }
  }
  public Dimension getPreferredSize() {
    return new Dimension(200, 200);
  }
  // Testing the BangBean:
  public static void main(String[] args) {
    BangBean bb = new BangBean();
    try {
      bb.addActionListener(new BBL());
    } catch(TooManyListenersException e) {}
    Frame aFrame = new Frame("BangBean Test");
    aFrame.addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          System.exit(0);
        }
      });
    aFrame.add(bb, BorderLayout.CENTER);
    aFrame.setSize(300,300);
    aFrame.setVisible(true);
  }
  // During testing, send action information
  // to the console:
  static class BBL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      System.out.println("BangBean action");
    }
  }
} ///:~ 

The


first thing you’ll notice is that


BangBean

implements the

Serializable
interface. This means that the application builder tool can
“pickle” all the information for the
BangBean
using serialization after the program designer has adjusted the values of the
properties. When the Bean is created as part of the running application, these
“pickled” properties are restored so that you get exactly what you
designed.

You


can see that all the fields are


private

,


which is what you’ll usually do with a Bean – allow access only


through methods, usually using the “property” scheme.

When


you look at the signature for


addActionListener( )

,


you’ll see that it can throw a

TooManyListenersException.
This indicates that it is
unicast,
which means it notifies only one listener when the event occurs. Ordinarily,
you’ll use
multicast
events so that many listeners can be notified of an event. However, that runs
into issues that you won’t be ready for until the next chapter, so it
will be revisited there (under the heading “Java Beans revisited”).
A unicast event sidesteps the problem.

When


you press the mouse, the text is put in the middle of the


BangBean

,


and if the


actionListener

field is not


null

,


its


actionPerformed( )

is called, creating a new

ActionEvent
object
in the process. Whenever the mouse is moved, its new coordinates are captured
and the canvas is repainted (erasing any text that’s on the canvas, as
you’ll see).

The


main( )

is added to allow you to test the program from the command line. When a Bean is


in a development environment,


main( )

will not be used, but it’s helpful to have a


main( )

in each of your Beans because it provides for rapid testing.


main( )

creates


a


Frame

and places a


BangBean

within it, attaching a simple


ActionListener

to the


BangBean

to print to the console whenever an


ActionEvent

occurs. Usually, of course, the application builder tool would create most of


the code that uses the Bean.

When


you run the


BangBean

through


BeanDumper

or put the


BangBean

inside a Bean-enabled development environment, you’ll notice that there


are many more properties and actions than are evident from the above code.


That’s because


BangBean

is inherited from


Canvas

,


and


Canvas

is a Bean, so you’re seeing its properties and events as well.


Packaging
a Bean

Before


you can bring a Bean into a Bean-enabled visual builder tool, it must be put


into the standard Bean container, which is a

JAR
(Java ARchive) file that includes all the Bean classes as well as a
“manifest” file that says “This is a Bean.” A manifest
file is simply a text file that follows a particular form. For the
BangBean,
the manifest file looks like this:
Manifest-Version: 1.0
 
Name: bangbean/BangBean.class
Java-Bean: True

The


first line indicates the version of the manifest scheme, which until further


notice from Sun is 1.0. The second line (empty lines are ignored) names the


BangBean.class

file, and the third says, “It’s a Bean.” Without the third


line, the program builder tool will not recognize the class as a Bean.

The


only tricky part is that you must make sure that you get the proper path in the


“Name:” field. If you look back at


BangBean.java

,


you’ll see it’s in


package
bangbean

(and


thus in a subdirectory called “bangbean” that’s off of the


classpath), and the name in the manifest file must include this package


information. In addition, you must place the manifest file in the directory


above

the root of your package path, which in this case means placing the file in the


directory above the “bangbean” subdirectory. Then you must invoke


jar

from the same directory as the

manifest
file, as follows:
jar
cfm BangBean.jar BangBean.mf bangbean

This


assumes that you want the resulting JAR file to be named


BangBean.jar

and that you’ve put the manifest in a file called


BangBean.mf

.

You


might wonder “What about all the other classes that were generated when I


compiled


BangBean.java

?”


Well, they all ended up inside the


bangbean

subdirectory, and you’ll see that the last argument for the above


jar

command line is the


bangbean

subdirectory. When you give


jar

the name of a subdirectory, it packages that entire subdirectory into the jar


file (including, in this case, the original


BangBean.java

source-code file – you might not choose to include the source with your


own Beans). In addition, if you turn around and unpack the JAR file


you’ve just created, you’ll discover that your manifest file


isn’t inside, but that


jar

has created its own manifest file (based partly on yours) called


MANIFEST.MF

and


placed it inside the subdirectory


META-INF

(for “meta-information”). If you open this manifest file


you’ll also notice that digital signature information has been added by


jar

for


each file, of the form:

Digest-Algorithms: SHA MD5
SHA-Digest: pDpEAG9NaeCx8aFtqPI4udSX/O0=
MD5-Digest: O4NcS1hE3Smnzlp2hj6qeg==

In


general, you don’t need to worry about any of this, and if you make


changes you can just modify your original manifest file and re-invoke


jar

to create a new JAR file for your Bean. You can also add other Beans to the JAR


file simply by adding their information to your manifest.

One


thing to notice is that you’ll probably want to put each Bean in its own


subdirectory, since when you create a JAR file you hand the


jar

utility the name of a subdirectory and it puts everything in that subdirectory


into the JAR file. You can see that both


Frog

and


BangBean

are in their own subdirectories.

Once


you have your Bean properly inside a JAR file you can bring it into a


Beans-enabled program-builder environment. The way you do this varies from one


tool to the next, but Sun provides a freely-available test bed for Java Beans


in their “Beans Development Kit” (BDK) called the “

beanbox.”
(Download the BDK from
www.javasoft.com.)
To place your Bean in the beanbox, copy the JAR file into the BDK’s
“jars” subdirectory before you start up the beanbox.

More
complex Bean support

You


can see how remarkably simple it is to make a Bean. But you aren’t


limited to what you’ve seen here. The Java Bean design provides a simple


point of entry but can also scale to more complex situations. These situations


are beyond the scope of this book but they will be briefly introduced here. You


can find more details at


http://java.sun.com/beans

.

One


place where you can add sophistication is with properties. The examples above


have shown only single properties, but it’s also possible to represent


multiple properties in an array. This is called an

indexed
property
.
You simply provide the appropriate methods (again following a naming convention
for the method names) and the
Introspector
recognizes an indexed property so your application builder tool can respond
appropriately.

Properties


can be

bound,
which means that they will notify other objects via a
PropertyChangeEvent.
The other objects can then choose to change themselves based on the change to
the Bean.

Properties


can be

constrained,
which means that other objects can veto a change to that property if it is
unacceptable. The other objects are notified using a
PropertyChangeEvent,
and they can throw a
ProptertyVetoException
to prevent the change from happening and to restore the old values.

You


can also change the way your Bean is represented at design time:

  1. You
    can provide a custom
    property sheet for your particular Bean. The ordinary property sheet will be
    used for all other Beans, but yours is automatically invoked when your Bean is
    selected.
  2. You
    can create a custom
    editor for a particular property, so the ordinary property sheet is used, but
    when your special property is being edited, your editor will automatically be
    invoked.
  3. You
    can provide a custom
    BeanInfo
    class for your Bean that produces information that’s different from the
    default created by the
    Introspector.
  4. It’s
    also possible to turn “expert” mode on and off in all FeatureDescriptors
    to distinguish between basic features and more complicated ones.

More
to Beans

There’s


another issue that couldn’t be addressed here. Whenever you create a


Bean, you should expect that it will be run in a multithreaded environment.


This means that you must understand the issues of threading, which will be


introduced in the next chapter. You’ll find a section there called


“Java Beans revisited” that will look at the problem and its


solution.


Contents

|

Prev

|

Next

Recommended for you...

Top Five Most Popular Front-end Frameworks
Tapas Pal
Mar 5, 2018
DocFlex/Javadoc: Multi-Format Doclet & Rapid Doclet Development Tool
CodeGuru Staff
Apr 23, 2012
Top Down with Memorization Complexity
CodeGuru Staff
Feb 24, 2012
Building and Using the Secret Service Java API
CodeGuru Staff
Feb 21, 2012
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.