Beanpublic class Bean extends Object This class encapsulates a bean object and its BeanInfo.
It is a key part of the ShowBean "beanbox" program, and demonstrates
how to instantiate and instrospect beans, and how to use reflection to
set properties and invoke methods. It also illustrates how to work with
PropertyEditor classes. |
Fields Summary |
---|
Object | bean | BeanInfo | info | Map | properties | Map | commands | boolean | expert | static final Object[] | NOARGS |
Constructors Summary |
---|
public Bean(Object bean, boolean expert)
// This constructor introspects the specified component.
// Typically you'll use one of the static factory methods instead.
this.bean = bean; // The object to instrospect
this.expert = expert; // Is the end-user an expert?
// Introspect to get BeanInfo for the bean
info = Introspector.getBeanInfo(bean.getClass());
// Now Create a map of property names to PropertyDescriptor objects
properties = new HashMap();
PropertyDescriptor[] props = info.getPropertyDescriptors();
for(int i = 0; i < props.length; i++) {
// Skip hidden properties, indexed properties, and expert
// properties unless the end-user is an expert.
if (props[i].isHidden()) continue;
if (props[i] instanceof IndexedPropertyDescriptor) continue;
if (!expert && props[i].isExpert()) continue;
properties.put(props[i].getDisplayName(), props[i]);
}
// Create a map of command names to MethodDescriptor objects
// Commands are methods with no arguments and no return value.
// We skip commands defined in Object, Component, Container, and
// JComponent because they contain methods that meet this definition
// but are not intended for end-users.
commands = new HashMap();
MethodDescriptor[] methods = info.getMethodDescriptors();
for(int i = 0; i < methods.length; i++) {
// Skip it if it is hidden or expert (unless user is expert)
if (methods[i].isHidden()) continue;
if (!expert && methods[i].isExpert()) continue;
Method m = methods[i].getMethod();
// Skip it if it has arguments or a return value
if (m.getParameterTypes().length > 0) continue;
if (m.getReturnType() != Void.TYPE) continue;
// Check the declaring class and skip useless superclasses
Class c = m.getDeclaringClass();
if (c==JComponent.class || c==Component.class ||
c==Container.class || c==Object.class) continue;
// Get the unqualifed classname to prefix method name with
String classname = c.getName();
classname = classname.substring(classname.lastIndexOf('.")+1);
// Otherwise, this is a valid command, so add it to the list
commands.put(classname + "." + m.getName(), methods[i]);
}
|
Methods Summary |
---|
public static je3.beans.Bean | forClassName(java.lang.String className, boolean expert)
// Load the named bean class
Class c = Class.forName(className);
// Instantiate it to create the component instance
Object bean = c.newInstance();
return new Bean(bean, expert);
| public static je3.beans.Bean | fromPersistentStream(java.io.InputStream in, boolean expert)
return new Bean(new XMLDecoder(in).readObject(), expert);
| public static je3.beans.Bean | fromSerializedStream(java.io.ObjectInputStream in, boolean expert)
return new Bean(in.readObject(), expert);
| public java.lang.Object | getBean() return bean;
| public java.lang.String | getCommandDescription(java.lang.String name)
MethodDescriptor m = (MethodDescriptor) commands.get(name);
if (m == null) throw new IllegalArgumentException(name);
return m.getShortDescription();
| public java.util.List | getCommandNames()
List names = new ArrayList(commands.keySet());
Collections.sort(names);
return names;
| public java.lang.String | getDisplayName()
return info.getBeanDescriptor().getDisplayName();
| public java.awt.Image | getIcon()
Image icon = info.getIcon(BeanInfo.ICON_COLOR_32x32);
if (icon != null) return icon;
else return info.getIcon(BeanInfo.ICON_COLOR_16x16);
| public java.lang.String | getPropertyDescription(java.lang.String name)
PropertyDescriptor p = (PropertyDescriptor) properties.get(name);
if (p == null) throw new IllegalArgumentException(name);
return p.getShortDescription();
| public java.awt.Component | getPropertyEditor(java.lang.String name)
// Get the descriptor for the named property; final for inner classes.
final PropertyDescriptor p = (PropertyDescriptor) properties.get(name);
if (p == null || isReadOnly(name)) // Make sure we can edit it.
throw new IllegalArgumentException(name);
// Find a PropertyEditor for the property
final PropertyEditor editor; // final for inner class use
if (p.getPropertyEditorClass() != null) {
// If there is a custom editor for this property instantiate one.
editor = (PropertyEditor)p.getPropertyEditorClass().newInstance();
}
else {
// Otherwise, look up an editor based on the property type
Class type = p.getPropertyType();
editor = PropertyEditorManager.findEditor(type);
// If there is no editor, give up
if (editor == null)
throw new UnsupportedOperationException("Can't set " +
"properties of type " +
type.getName());
}
// Get the property accessor methods for this property so we can
// query the initial value and set the edited value
final Method getter = p.getReadMethod();
final Method setter = p.getWriteMethod();
// Use Java reflection to find the current propery value. Then tell
// the property editor about it.
Object currentValue = getter.invoke(bean, NOARGS);
editor.setValue(currentValue);
// If the PropertyEditor has a custom editor, then we'll just return
// that custom editor component from this method. User changes to the
// component change the value in the PropertyEditor which generates
// a PropertyChangeEvent. We register a listener so that these changes
// set the property on the bean as well.
if (editor.supportsCustomEditor()) {
final Component editComponent = editor.getCustomEditor();
// Note that we register the listener on the PropertyEditor, not
// on its custom editor Component.
editor.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
try {
// Pass edited value to property setter
Object editedValue = editor.getValue();
setter.invoke(bean, new Object[] { editedValue});
}
catch(Exception ex) {
JOptionPane.showMessageDialog(editComponent,
ex, ex.getClass().getName(),
JOptionPane.ERROR_MESSAGE);
}
}
});
return editComponent;
}
// Otherwise, if the PropertyEditor is for an enumerated type based
// on a fixed list of possible values, then return a JComboBox
// component that allows the user to select one of the values.
final String[] tags = editor.getTags();
if (tags != null) {
// Create the component
final JComboBox combobox = new JComboBox(tags);
// Use the current value of the property as the currently selected
// item in the combo box.
combobox.setSelectedItem(editor.getAsText());
// Add a listener to hook the combo box up to the property. When
// the user selects an item, set the property value.
combobox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
// Ignore deselect events
if (e.getStateChange() == ItemEvent.DESELECTED) return;
try {
// Get the user's selected string from combo box
String selectedTag =
(String)combobox.getSelectedItem();
// Tell the editor about this string value
editor.setAsText(selectedTag);
// Ask the editor to convert to the property type
Object editedValue = editor.getValue();
// Pass this value to the property setter method
setter.invoke(bean, new Object[] { editedValue });
}
catch(Exception ex) {
JOptionPane.showMessageDialog(combobox,
ex, ex.getClass().getName(),
JOptionPane.ERROR_MESSAGE);
}
}
});
return combobox;
}
// Otherwise, property type is not enumerated, and we use a JTextField
// to allow the user to enter arbitrary text for conversion by the
// setAsText() method of the PropertyEditor
final JTextField textfield = new JTextField();
// Display the current value of the property in the field
textfield.setText(editor.getAsText());
// Hook the JTextField up to the PropertyEditor.
textfield.addActionListener(new ActionListener() {
// This is called when the user strikes the Enter key
public void actionPerformed(ActionEvent e) {
try {
// Get the user's input from the text field
String newText = textfield.getText();
// Tell the editor about it
editor.setAsText(newText);
// Ask the editor to convert to the property type
Object editedValue = editor.getValue();
// Pass this value to the property setter method
setter.invoke(bean, new Object[] { editedValue });
}
catch(Exception ex) {
JOptionPane.showMessageDialog(textfield,
ex, ex.getClass().getName(),
JOptionPane.ERROR_MESSAGE);
}
}
});
return textfield;
| public java.util.List | getPropertyNames()
// Make a List from a Set (from a Map), and sort it before returning.
List names = new ArrayList(properties.keySet());
Collections.sort(names);
return names;
| public java.lang.String | getPropertyValue(java.lang.String name)
PropertyDescriptor p = (PropertyDescriptor) properties.get(name);
if (p == null) throw new IllegalArgumentException(name);
Method m = p.getReadMethod(); // property accessor method
Object value = m.invoke(bean, NOARGS); // invoke it to get value
if (value == null) return "null";
return value.toString(); // use the toString method()
| public java.lang.String | getShortDescription()
return info.getBeanDescriptor().getShortDescription();
| public void | invokeCommand(java.lang.String name)
MethodDescriptor method = (MethodDescriptor) commands.get(name);
if (method == null) throw new IllegalArgumentException(name);
Method m = method.getMethod();
m.invoke(bean, NOARGS);
| public boolean | isReadOnly(java.lang.String name)
PropertyDescriptor p = (PropertyDescriptor) properties.get(name);
if (p == null) throw new IllegalArgumentException(name);
return p.getWriteMethod() == null;
| public void | setPropertyValue(java.lang.String name, java.lang.String value)
// Get the descriptor for the named property
PropertyDescriptor p = (PropertyDescriptor) properties.get(name);
if (p == null || isReadOnly(name)) // Make sure we can set it
throw new IllegalArgumentException(name);
Object v; // Store the converted string value here.
Class type = p.getPropertyType();
// Convert common types in well-known ways
if (type == String.class) v = value;
else if (type == boolean.class) v = Boolean.valueOf(value);
else if (type == byte.class) v = Byte.valueOf(value);
else if (type == char.class) v = new Character(value.charAt(0));
else if (type == short.class) v = Short.valueOf(value);
else if (type == int.class) v = Integer.valueOf(value);
else if (type == long.class) v = Long.valueOf(value);
else if (type == float.class) v = Float.valueOf(value);
else if (type == double.class) v = Double.valueOf(value);
else if (type == Color.class) v = Color.decode(value);
else if (type == Font.class) v = Font.decode(value);
else {
// Try to find a property editor for unknown types
PropertyEditor editor = PropertyEditorManager.findEditor(type);
if (editor != null) {
editor.setAsText(value);
v = editor.getValue();
}
// Otherwise, give up.
else throw new UnsupportedOperationException("Can't set " +
"properties of type "+
type.getName());
}
// Now get the Method object for the property setter method and
// invoke it on the bean object, passing the converted value.
Method setter = p.getWriteMethod();
setter.invoke(bean, new Object[] { v });
|
|