Java/Development Class/Java Beans
Содержание
- 1 An extension of ArrayList that provides some handy utilities for working with JavaBeans
- 2 An extension of Vector that provides some handy utilities for working with JavaBeans
- 3 Bean Container
- 4 Bean has a single property called property.
- 5 Bean Utility
- 6 Convert a bean to XML persistence
- 7 Convert an XML persistence to bean
- 8 Create an instance a Bean
- 9 Deserializing a Bean from XML
- 10 Determine bean"s property type
- 11 Displaying the Current Directory in the Title of a JFileChooser Dialog
- 12 extends SimpleBeanInfo
- 13 Get a list of selected files
- 14 Get and set an Object type property
- 15 Get and set properties on a bean
- 16 Get and set the value of a property in a bean using Expression and Statement
- 17 gets and sets an array type property
- 18 gets and sets a primitive type property
- 19 Getting and Setting a Property of a Bean
- 20 Implementing a Bound Property
- 21 Implementing a Constrained Property: fires a PropertyChangeEvent whenever its value is about to be changed.
- 22 Instantiating a Bean
- 23 Introspecting a Bean
- 24 Is JavaBean Compliant Setter
- 25 JavaBean: BeanContextSupport
- 26 JavaBean: creates all of the objects, a tests the service capabilities
- 27 JavaBean: how to use the instantiateChild() convenience method to create a bean
- 28 JavaBean: illustrate delivery of the BeanContextMembershipEvent
- 29 JavaBean: Test program that adds 100 beans to a context
- 30 Listen for a constrained property change
- 31 Listen for bean"s property change event
- 32 Listening for a Property Change Event: A property change event is fired when a bound property is changed.
- 33 Listening for a Vetoable Property Change Event
- 34 Listening for Changes to the Current Directory in a JFileChooser Dialog
- 35 Listening for Changes to the Selected File in a JFileChooser Dialog
- 36 Listing the Property Names of a Bean
- 37 List property names of a Bean
- 38 Prevent bean"s property being serialized to XML
- 39 Preventing a Bean Property from Being Serialized to XML
- 40 PropertyTable
- 41 Read bean"s property value
- 42 Saving and restoring the state of a pretend CAD system
- 43 Serializing a Bean to XML: XMLEncoder only persists the value of public properties.
- 44 Serializing an Immutable Bean Property to XML
- 45 Setting an Accessory Component in a JFileChooser Dialog
An extension of ArrayList that provides some handy utilities for working with JavaBeans
/*
* BeanArrayList.java
*
* Created on May 21, 2004, 7:23 PM
*
* Copyright (C) 2004, 2005 Robert Cooper, Temple of the Screaming Penguin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyDescriptor;
import java.lang.ruparable;
import java.lang.reflect.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.ArrayList;
/** This is an extension of ArrayList that provides some handy utilities for working with JavaBeans.
* Includes basic statistical information, page chunking and storing and can also be used as a manager for
* indexed properies and supports PropertyChangeEvents.
*
* @version $Rev: 79 $
* @author
*/
public class BeanArrayList<T> extends ArrayList<T> {
/**
* DOCUMENT ME!
*/
Collection source;
/**
* DOCUMENT ME!
*/
private PropertyChangeSupport changes;
/**
* DOCUMENT ME!
*/
private String indexPropertyName;
/**
* DOCUMENT ME!
*/
private int nextChunk = -1;
/**
* DOCUMENT ME!
*/
private int numberOfChunks = 1;
/**
* DOCUMENT ME!
*/
private int previousChunk = -1;
/** No Args Contstructor */
public BeanArrayList() {
super();
}
/**
* This contructs a new BeanArrayList with PropertyChangeEvent support.
* @param indexPropertyName the property name of the parent object to fire events for
* @param changeOwner the owner object that change events should "come from"
*/
public BeanArrayList(String indexPropertyName,Object changeOwner) {
this();
this.indexPropertyName = indexPropertyName;
this.changes = new PropertyChangeSupport(changeOwner);
}
/**
* Creates a new instance of BeanArrayList prepopulating off a
* collection, limited to only the desired chunk.
* @param source Collection to read from
* @param chunkSize int number of object to return.
* @param currentChunk int value of the chunk to get (zero index)
*/
public BeanArrayList(int chunkSize,int currentChunk,Collection<T> source) {
super();
this.source = source;
Iterator<T> itr = source.iterator();
if(source.size() > 0) {
this.numberOfChunks = source.size() / chunkSize;
if((source.size() % chunkSize) > 0) {
this.numberOfChunks++;
}
//spin
for(int i = 0; i < (chunkSize * currentChunk); i++) {
if(!itr.hasNext()) {
continue;
}
itr.next();
}
for(int i = 0; i < chunkSize; i++) {
if(!itr.hasNext()) {
continue;
}
this.add(itr.next());
}
if(currentChunk != 0) {
previousChunk = currentChunk - 1;
}
if(source.size() > ((currentChunk + 1) * chunkSize)) {
nextChunk = currentChunk + 1;
}
}
}
/**
* Creates a new instance of BeanArrayList prepopulating off a
* collection, limited to only the desired chunk, and includes
* PropertyChangeEvent support.
* @param indexPropertyName the property name of the parent object to fire events for
* @param changeOwner the object change events should come from
* @param chunkSize number of objects to return
* @param currentChunk int value of the chunk to get (zero index)
* @param source source Collection to read from.
*/
public BeanArrayList(String indexPropertyName,Object changeOwner,int chunkSize,int currentChunk,Collection<T> source) {
this(chunkSize,currentChunk,source);
this.indexPropertyName = indexPropertyName;
this.changes = new PropertyChangeSupport(changeOwner);
}
/** Creates a new instance of BeanArrayList
* @param source Collection containing the initial values.
*/
public BeanArrayList(Collection<T> source) {
this(source.size(),0,source);
}
/**
* This contructs a new BeanArrayList with PropertyChangeEvent support.
* @param indexPropertyName the property name of the parent object to fire events for
* @param changeOwner the object change events should come from
* @param source Collection to prepopulate from.
*/
public BeanArrayList(String indexPropertyName,Object changeOwner,Collection<T> source) {
this(source);
this.indexPropertyName = indexPropertyName;
this.changes = new PropertyChangeSupport(changeOwner);
}
/**
* Gets a chunk of this ArrayList.
* @param chunkSize int number of object to return.
* @param currentChunk int value of the chunk to get (zero index)
* @return new BeanArrayList representing the chunk requested.
*/
public BeanArrayList getChunk(int chunkSize,int currentChunk) {
return new BeanArrayList(chunkSize,currentChunk,this);
}
/**
* Overrides the parent to support PropertyChangeEvents
* @param obj new object value
* @param index index position to place the object
*/
public void setElementAt(T obj,int index) {
T old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.get(index);
}
super.set(index, obj);
if(old != null) {
changes.fireIndexedPropertyChange(this.indexPropertyName,index,old,obj);
}
}
/**
* Filters a property using the Comparable.rupareTo() on the porperty to
* test for a range
* @param propertyName property to filter on
* @param inclusive include the values of the range limiters
* @param fromValue low range value
* @param toValue high range value
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return new BeanArrayList filtered on the range
*/
public BeanArrayList<T> getFiltered(String propertyName,boolean inclusive,Comparable fromValue,Comparable toValue) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
HashMap cache = new HashMap();
String currentClass = "";
PropertyDescriptor pd = null;
BeanArrayList<T> results = new BeanArrayList<T>();
for(int i = 0; i < this.size(); i++) {
T o = this.get(i);
if(!currentClass.equals(o.getClass().getName())) {
pd = (PropertyDescriptor)cache.get(o.getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
cache.put(o.getClass().getName(),pd);
foundProperty = true;
}
}
}
}
Comparable value = (Comparable)pd.getReadMethod().invoke(o);
if((value.rupareTo(fromValue) > 0)&&(value.rupareTo(toValue) < 0)) {
results.add(o);
} else if(inclusive&&((value.rupareTo(fromValue) == 0)||(value.rupareTo(toValue) == 0))) {
results.add(o);
}
}
return results;
}
/**
* This method does a string match on values of a property.
* @param propertyName String value containing the name of the property to match.
* @param match Value to search for. This is a case-insensitive value that takes % as a multiple character wildcard value.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return a new BeanArrayList filtered on the specified property
*/
public BeanArrayList<T> getFilteredStringMatch(String propertyName,String match) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
HashMap cache = new HashMap();
String currentClass = "";
PropertyDescriptor pd = null;
BeanArrayList<T> results = new BeanArrayList<T>();
for(int i = 0; i < this.size(); i++) {
T o = this.get(i);
if(!currentClass.equals(o.getClass().getName())) {
pd = (PropertyDescriptor)cache.get(o.getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
cache.put(o.getClass().getName(),pd);
foundProperty = true;
}
}
}
}
String value = pd.getReadMethod().invoke(o).toString().toLowerCase();
StringTokenizer st = new StringTokenizer(match.toLowerCase(),"%");
boolean isMatch = true;
int matchIndex = 0;
while(st.hasMoreTokens()&&isMatch) {
String tk = st.nextToken();
if(value.indexOf(tk,matchIndex) == -1) {
isMatch = false;
} else {
matchIndex = value.indexOf(tk,matchIndex) + tk.length();
}
}
if(isMatch) {
results.add(o);
}
}
return results;
}
/**
* This method returns the average value of a numerical property.
* @param propertyName String value of the property name to calculate.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return Average of property values.
*/
public Number getMeanOfProperty(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
double mean = this.getSumOfProperty(propertyName).doubleValue() / this.size();
return new Double(mean);
}
/**
* This method returns the index of the bean with the median value
* on the specified property.
*
* <p>If there is an odd number of items in the dataset, the one below
* the 50% mark will be returned. The true mathmatical mean, therefore
* would be:
* <code>
* (beanArrayList.get(x).getProperty() + beanArrayList.get(x+1).getProperty() )/2
* </code></p>
* @param propertyName String value of the property name to calculate.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return int value of the median index of the ArrayList
*/
public int getMedianIndex(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
BeanArrayList bv = new BeanArrayList(this.size(),0,this);
bv.sortOnProperty(propertyName);
int orderedIndex = bv.size() / 2;
Object o = bv.get(orderedIndex);
return this.indexOf(o);
}
/**
* This method returns the index of an object representing the
* mode value of a property name.
* @param propertyName String value of the property name to calculate.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return int value of the mode index
*/
public int getModeIndex(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
int index = -1;
int max = 0;
int count = 0;
Object o = null;
Object hold = null;
HashMap cache = new HashMap();
String currentClass = "";
PropertyDescriptor pd = null;
BeanArrayList bv = new BeanArrayList(this.size(),0,this);
bv.sortOnProperty(propertyName);
for(int i = 0; i < bv.size(); i++) {
if(!currentClass.equals(bv.get(i).getClass().getName())) {
pd = (PropertyDescriptor)cache.get(bv.get(i).getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(bv.get(i).getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
cache.put(bv.get(i).getClass().getName(),pd);
foundProperty = true;
}
}
}
}
if(hold == null) {
hold = pd.getReadMethod().invoke(bv.get(i));
} else {
o = pd.getReadMethod().invoke(bv.get(i));
if((o != null)&&o.equals(hold)) {
count++;
if(count > max) {
max = count;
index = this.indexOf(bv.get(i));
}
} else {
count = 1;
}
hold = o;
}
}
return index;
}
/** Returns -1 or the the index of the next chunk after the current
* ArrayList.
* @return -1 or the the index of the next chunk after the current ArrayList
*/
public int getNextChunk() {
return this.nextChunk;
}
/**
* returns the number of chunks in the ArrayList
* @return int value number of chunks
*/
public int getNumberOfChunks() {
return this.numberOfChunks;
}
/** Returns -1 or the the index of the previous chunk before the
* current ArrayList.
* @return -1 or the the index of the previous chunk before the
* current ArrayList
*/
public int getPreviousChunk() {
return this.previousChunk;
}
/**
* This method returns the sum of all values of a numerical
* property.
* @param propertyName String value of the property name to calculate.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return sum of a numerical property
*/
public Number getSumOfProperty(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
double d = 0.0;
String currentClass = "";
PropertyDescriptor pd = null;
for(int i = 0; i < this.size(); i++) {
T o = this.get(i);
if(!currentClass.equals(o.getClass().getName())) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty; pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
foundProperty = true;
}
}
}
if(o != null) {
Number n = (Number)pd.getReadMethod().invoke(o);
d += n.doubleValue();
}
}
return new Double(d);
}
/**
* Inserts the specified element at the specified position in this ArrayList.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
* @since 1.2
* @param index index at which the specified element is to be inserted.
* @param element element to be inserted.
*/
public void add(int index,T element) {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
super.add(index,element);
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
/**
* Appends the specified element to the end of this ArrayList.
*
* @param o element to be appended to this ArrayList.
* @return true (as per the general contract of Collection.add).
* @since 1.2
*/
public boolean add(T o) {
boolean retValue;
retValue = super.add(o);
if((this.indexPropertyName != null)&&(this.changes != null)) {
changes.fireIndexedPropertyChange(this.indexPropertyName,this.size() - 1,null,o);
}
return retValue;
}
/**
* Appends all of the elements in the specified Collection to the end of
* this ArrayList, in the order that they are returned by the specified
* Collection"s Iterator. The behavior of this operation is undefined if
* the specified Collection is modified while the operation is in progress.
* (This implies that the behavior of this call is undefined if the
* specified Collection is this ArrayList, and this ArrayList is nonempty.)
*
* @return <tt>true</tt> if this ArrayList changed as a result of the call.
* @since 1.2
* @param c elements to be inserted into this ArrayList.
*/
public boolean addAll(Collection<? extends T> c) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.addAll(c);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Inserts all of the elements in the specified Collection into this
* ArrayList at the specified position. Shifts the element currently at
* that position (if any) and any subsequent elements to the right
* (increases their indices). The new elements will appear in the ArrayList
* in the order that they are returned by the specified Collection"s
* iterator.
*
* @return <tt>true</tt> if this ArrayList changed as a result of the call.
* @since 1.2
* @param index index at which to insert first element
* from the specified collection.
* @param c elements to be inserted into this ArrayList.
*/
public boolean addAll(int index,Collection<? extends T> c) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.addAll(index,c);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Registers propertyChangeListeners to be fired when something changes in the ArrayList.
* Note, the whole ArrayList is an "indexedProperty" name specified and parent delineated in
* the constructor.
* @param listener PropertyChangeListener to register
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
changes.addPropertyChangeListener(listener);
}
/**
* Registers propertyChangeListeners to be fired when something changes in the ArrayList.
* Note, the whole ArrayList is an "indexedProperty" name specified and parent delineated in
* the constructor.
* @param property propteryName must match what the property name of this ArrayList is or the listener will be ignored.
* @param listener the listener to register
*/
public void addPropertyChangeListener(String property,PropertyChangeListener listener) {
if((property != null)&&property.equals(this.indexPropertyName)) {
changes.addPropertyChangeListener(property,listener);
}
}
/**
* This method reverses the order of the ArrayList.
*/
public synchronized void invert() {
BeanArrayList<T> temp = new BeanArrayList<T>(this);
for(int i = 0; i < this.size(); i++) {
this.set(i, temp.get( temp.size() -1 ) );
temp.remove( temp.get( temp.size() -1 ) );
}
}
/**
* Removes the first occurrence of the specified element in this ArrayList
* If the ArrayList does not contain the element, it is unchanged. More
* formally, removes the element with the lowest index i such that
* <code>(o==null ? get(i)==null : o.equals(get(i)))</code> (if such
* an element exists).
*
* @param o element to be removed from this ArrayList, if present.
* @return true if the ArrayList contained the specified element.
* @since 1.2
*/
public boolean remove(Object o) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.remove(o);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Removes the element at the specified position in this ArrayList.
* shifts any subsequent elements to the left (subtracts one from their
* indices). Returns the element that was removed from the ArrayList.
*
* @return element that was removed
* @since 1.2
* @param index the index of the element to removed.
*/
public T remove(int index) {
T retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.remove(index);
if((retValue != null)&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Removes from this ArrayList all of its elements that are contained in the
* specified Collection.
*
* @return true if this ArrayList changed as a result of the call.
* @since 1.2
* @param c a collection of elements to be removed from the ArrayList
*/
public boolean removeAll(Collection<? > c) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.removeAll(c);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Removes all components from this ArrayList and sets its size to zero.<p>
*
* This method is identical in functionality to the clear method
* (which is part of the List interface).
*
* @see #clear
* @see List
*/
public void removeAllElements() {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
super.clear();
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
/**
* Removes the first (lowest-indexed) occurrence of the argument
* from this ArrayList. If the object is found in this ArrayList, each
* component in the ArrayList with an index greater or equal to the
* object"s index is shifted downward to have an index one smaller
* than the value it had previously.<p>
*
* This method is identical in functionality to the remove(Object)
* method (which is part of the List interface).
*
* @param obj the component to be removed.
* @return <code>true</code> if the argument was a component of this
* ArrayList; <code>false</code> otherwise.
* @see List#remove(Object)
* @see List
*/
public boolean removeElement(Object obj) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.remove(obj);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Deletes the component at the specified index. Each component in
* this ArrayList with an index greater or equal to the specified
* <code>index</code> is shifted downward to have an index one
* smaller than the value it had previously. The size of this ArrayList
* is decreased by <tt>1</tt>.<p>
*
* The index must be a value greater than or equal to <code>0</code>
* and less than the current size of the ArrayList. <p>
*
* This method is identical in functionality to the remove method
* (which is part of the List interface). Note that the remove method
* returns the old value that was stored at the specified position.
*
* @see #size()
* @see #remove(int)
* @see List
* @param index the index of the object to remove.
*/
public void removeElementAt(int index) {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
super.remove(index);
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
/**
* Removes propertyChangeListeners to be fired when something changes in the ArrayList.
* Note, the whole ArrayList is an "indexedProperty" name specified and parent delineated in
* the constructor.
* @param listener listener to remove
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
changes.removePropertyChangeListener(listener);
}
/**
* Removes propertyChangeListeners to be fired when something changes in the ArrayList.
* Note, the whole ArrayList is an "indexedProperty" name specified and parent delineated in
* the constructor.
* @param property must match the current property name for the ArrayList or will be ignored
* @param listener listener to remove
*/
public void removePropertyChangeListener(String property,PropertyChangeListener listener) {
if((property != null)&&property.equals(this.indexPropertyName)) {
changes.removePropertyChangeListener(property,listener);
}
}
/**
* Resets the contents of the ArrayList to the values provided.
* @param contents Array of object to replace the current contents with
*/
public synchronized void resetContents(T[] contents) {
if((this.indexPropertyName != null)&&(this.changes != null)) {
changes.firePropertyChange(this.indexPropertyName,this.toTypedArray(),contents);
}
this.removeAllElements();
for(T t : contents)
this.add(t);
}
/**
* Retains only the elements in this ArrayList that are contained in the
* specified Collection. In other words, removes from this ArrayList all
* of its elements that are not contained in the specified Collection.
*
* @return true if this ArrayList changed as a result of the call.
* @since 1.2
* @param c a collection of elements to be retained in this ArrayList
* (all other elements are removed)
*/
public boolean retainAll(Collection<? > c) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.retainAll(c);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Replaces the element at the specified position in this ArrayList with the
* specified element.
*
* @return the element previously at the specified position.
* @since 1.2
* @param index index of element to replace.
* @param element element to be stored at the specified position.
*/
public T set(int index,T element) {
T retValue;
retValue = super.set(index,element);
if((this.indexPropertyName != null)&&(this.changes != null)) {
changes.fireIndexedPropertyChange(this.indexPropertyName,index,retValue,element);
}
return retValue;
}
/**
* performs a selection sort on all the beans in the ArrayList by PropertyName
*
* <p>You can use a mixture of bean classes as long as all the beans support
* the same property (getName() for instance), and all have the same return
* type.</p>
*
* <p>For optimal performance, it is recommended that if you have a
* mixed class set the you have them grouped with like classes together as this
* will minimize reflection inspections.</p>
* @param propertyName String value containing the property to sort
* on.
* @throws java.lang.IllegalAccessException Property was not accessible
* @throws java.beans.IntrospectionException Couldn"t introspect
* @throws java.lang.reflect.InvocationTargetException Is the proper signature getProperty() ?
*/
public void sortOnProperty(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
this.sortOnProperty(propertyName,true);
}
/**
* performs a selection sort on all the beans in the ArrayList by
* PropertyName
*
* <p>You can use a mixture of bean classes as long as all the beans
* support the same property (getName() for instance), and all have the
* same return type, or can be compareTo()ed each other.</p>
*
* <p>For optimal performance, it is recommended that if you have a
* mixed class set the you have them grouped with like classes together
* as this will minimize reflection inspections.</p>
* @param propertyName String value containing the property to sort on.
* @param ascending == sorts up if true, down if not.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
*/
public synchronized void sortOnProperty(String propertyName,boolean ascending) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
T temp = null;
String currentClass = "";
PropertyDescriptor pd = null;
HashMap cache = new HashMap();
for(int i = 0; i < (this.size() - 1); i++) {
for(int j = i + 1; j < this.size(); j++) {
T o1 = this.get(i);
if(!currentClass.equals(o1.getClass().getName())) {
pd = (PropertyDescriptor)cache.get(o1.getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o1.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
cache.put(o1.getClass().getName(),pd);
foundProperty = true;
}
}
}
}
//System.out.println( "o1: "+o1+" "+pd);
//System.out.println( propertyName +" "+ (pd == null ));
Comparable oc1 = (Comparable)pd.getReadMethod().invoke(o1);
T o2 = this.get(j);
if(!currentClass.equals(o2.getClass().getName())) {
pd = (PropertyDescriptor)cache.get(o2.getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o2.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
foundProperty = true;
}
}
}
}
Comparable oc2 = (Comparable)pd.getReadMethod().invoke(o2);
if(ascending) {
if((oc1 != oc2)&&((oc2 == null)||((oc1 != null)&&(oc2 != null)&&(oc2.rupareTo(oc1) < 0)))) { //swap
this.setElementAt(o2,i);
this.setElementAt(o1,j);
}
} else {
if((oc1 != oc2)&&((oc1 == null)||((oc1 != null)&&(oc2 != null)&&(oc1.rupareTo(oc2) < 0)))) { //swap
this.setElementAt(o2,i);
this.setElementAt(o1,j);
}
}
}
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
}
/**
* Returns an Array of the generic type associated with this ArrayList.
* @return Array representation of the current ArrayList.
*/
public T[] toTypedArray() {
return (T[])this.toArray();
}
/**
* Removes from this List all of the elements whose index is between
* fromIndex, inclusive and toIndex, exclusive. Shifts any succeeding
* elements to the left (reduces their index).
* This call shortens the ArrayList by (toIndex - fromIndex) elements. (If
* toIndex==fromIndex, this operation has no effect.)
*
* @param fromIndex index of first element to be removed.
* @param toIndex index after last element to be removed.
*/
protected void removeRange(int fromIndex,int toIndex) {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
super.removeRange(fromIndex,toIndex);
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
}
An extension of Vector that provides some handy utilities for working with JavaBeans
/*
* BeanVector.java
*
* Created on May 21, 2004, 7:23 PM
*
* Copyright (C) 2004, 2005 Robert Cooper, Temple of the Screaming Penguin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyDescriptor;
import java.lang.ruparable;
import java.lang.reflect.*;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.Vector;
/** This is an extension of Vector that provides some handy utilities for working with JavaBeans.
* Includes basic statistical information, page chunking and storing and can also be used as a manager for
* indexed properies and supports PropertyChangeEvents.
*
* @version $Rev: 79 $
* @author
*/
public class BeanVector<T> extends Vector<T> {
/**
* DOCUMENT ME!
*/
Collection source;
/**
* DOCUMENT ME!
*/
private PropertyChangeSupport changes;
/**
* DOCUMENT ME!
*/
private String indexPropertyName;
/**
* DOCUMENT ME!
*/
private int nextChunk = -1;
/**
* DOCUMENT ME!
*/
private int numberOfChunks = 1;
/**
* DOCUMENT ME!
*/
private int previousChunk = -1;
/** No Args Contstructor */
public BeanVector() {
super();
}
/**
* This contructs a new BeanVector with PropertyChangeEvent support.
* @param indexPropertyName the property name of the parent object to fire events for
* @param changeOwner the owner object that change events should "come from"
*/
public BeanVector(String indexPropertyName,Object changeOwner) {
this();
this.indexPropertyName = indexPropertyName;
this.changes = new PropertyChangeSupport(changeOwner);
}
/**
* Creates a new instance of BeanVector prepopulating off a
* collection, limited to only the desired chunk.
* @param source Collection to read from
* @param chunkSize int number of object to return.
* @param currentChunk int value of the chunk to get (zero index)
*/
public BeanVector(int chunkSize,int currentChunk,Collection<T> source) {
super();
this.source = source;
Iterator<T> itr = source.iterator();
if(source.size() > 0) {
this.numberOfChunks = source.size() / chunkSize;
if((source.size() % chunkSize) > 0) {
this.numberOfChunks++;
}
//spin
for(int i = 0; i < (chunkSize * currentChunk); i++) {
if(!itr.hasNext()) {
continue;
}
itr.next();
}
for(int i = 0; i < chunkSize; i++) {
if(!itr.hasNext()) {
continue;
}
this.add(itr.next());
}
if(currentChunk != 0) {
previousChunk = currentChunk - 1;
}
if(source.size() > ((currentChunk + 1) * chunkSize)) {
nextChunk = currentChunk + 1;
}
}
}
/**
* Creates a new instance of BeanVector prepopulating off a
* collection, limited to only the desired chunk, and includes
* PropertyChangeEvent support.
* @param indexPropertyName the property name of the parent object to fire events for
* @param changeOwner the object change events should come from
* @param chunkSize number of objects to return
* @param currentChunk int value of the chunk to get (zero index)
* @param source source Collection to read from.
*/
public BeanVector(String indexPropertyName,Object changeOwner,int chunkSize,int currentChunk,Collection<T> source) {
this(chunkSize,currentChunk,source);
this.indexPropertyName = indexPropertyName;
this.changes = new PropertyChangeSupport(changeOwner);
}
/** Creates a new instance of BeanVector
* @param source Collection containing the initial values.
*/
public BeanVector(Collection<T> source) {
this(source.size(),0,source);
}
/**
* This contructs a new BeanVector with PropertyChangeEvent support.
* @param indexPropertyName the property name of the parent object to fire events for
* @param changeOwner the object change events should come from
* @param source Collection to prepopulate from.
*/
public BeanVector(String indexPropertyName,Object changeOwner,Collection<T> source) {
this(source);
this.indexPropertyName = indexPropertyName;
this.changes = new PropertyChangeSupport(changeOwner);
}
/**
* Gets a chunk of this vector.
* @param chunkSize int number of object to return.
* @param currentChunk int value of the chunk to get (zero index)
* @return new BeanVector representing the chunk requested.
*/
public BeanVector getChunk(int chunkSize,int currentChunk) {
return new BeanVector(chunkSize,currentChunk,this);
}
/**
* Overrides the parent to support PropertyChangeEvents
* @param obj new object value
* @param index index position to place the object
*/
public void setElementAt(T obj,int index) {
T old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.elementAt(index);
}
super.setElementAt(obj,index);
if(old != null) {
changes.fireIndexedPropertyChange(this.indexPropertyName,index,old,obj);
}
}
/**
* Filters a property using the Comparable.rupareTo() on the porperty to
* test for a range
* @param propertyName property to filter on
* @param inclusive include the values of the range limiters
* @param fromValue low range value
* @param toValue high range value
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return new BeanVector filtered on the range
*/
public BeanVector<T> getFiltered(String propertyName,boolean inclusive,Comparable fromValue,Comparable toValue) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
Hashtable cache = new Hashtable();
String currentClass = "";
PropertyDescriptor pd = null;
BeanVector<T> results = new BeanVector<T>();
for(int i = 0; i < this.size(); i++) {
T o = this.elementAt(i);
if(!currentClass.equals(o.getClass().getName())) {
pd = (PropertyDescriptor)cache.get(o.getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
cache.put(o.getClass().getName(),pd);
foundProperty = true;
}
}
}
}
Comparable value = (Comparable)pd.getReadMethod().invoke(o);
if((value.rupareTo(fromValue) > 0)&&(value.rupareTo(toValue) < 0)) {
results.add(o);
} else if(inclusive&&((value.rupareTo(fromValue) == 0)||(value.rupareTo(toValue) == 0))) {
results.add(o);
}
}
return results;
}
/**
* This method does a string match on values of a property.
* @param propertyName String value containing the name of the property to match.
* @param match Value to search for. This is a case-insensitive value that takes % as a multiple character wildcard value.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return a new BeanVector filtered on the specified property
*/
public BeanVector<T> getFilteredStringMatch(String propertyName,String match) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
Hashtable cache = new Hashtable();
String currentClass = "";
PropertyDescriptor pd = null;
BeanVector<T> results = new BeanVector<T>();
for(int i = 0; i < this.size(); i++) {
T o = this.elementAt(i);
if(!currentClass.equals(o.getClass().getName())) {
pd = (PropertyDescriptor)cache.get(o.getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
cache.put(o.getClass().getName(),pd);
foundProperty = true;
}
}
}
}
String value = pd.getReadMethod().invoke(o).toString().toLowerCase();
StringTokenizer st = new StringTokenizer(match.toLowerCase(),"%");
boolean isMatch = true;
int matchIndex = 0;
while(st.hasMoreTokens()&&isMatch) {
String tk = st.nextToken();
if(value.indexOf(tk,matchIndex) == -1) {
isMatch = false;
} else {
matchIndex = value.indexOf(tk,matchIndex) + tk.length();
}
}
if(isMatch) {
results.add(o);
}
}
return results;
}
/**
* This method returns the average value of a numerical property.
* @param propertyName String value of the property name to calculate.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return Average of property values.
*/
public Number getMeanOfProperty(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
double mean = this.getSumOfProperty(propertyName).doubleValue() / this.size();
return new Double(mean);
}
/**
* This method returns the index of the bean with the median value
* on the specified property.
*
* <p>If there is an odd number of items in the dataset, the one below
* the 50% mark will be returned. The true mathmatical mean, therefore
* would be:
* <code>
* (beanVector.elementAt(x).getProperty() + beanVector.elementAt(x+1).getProperty() )/2
* </code></p>
* @param propertyName String value of the property name to calculate.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return int value of the median index of the Vector
*/
public int getMedianIndex(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
BeanVector bv = new BeanVector(this.size(),0,this);
bv.sortOnProperty(propertyName);
int orderedIndex = bv.size() / 2;
Object o = bv.elementAt(orderedIndex);
return this.indexOf(o);
}
/**
* This method returns the index of an object representing the
* mode value of a property name.
* @param propertyName String value of the property name to calculate.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return int value of the mode index
*/
public int getModeIndex(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
int index = -1;
int max = 0;
int count = 0;
Object o = null;
Object hold = null;
Hashtable cache = new Hashtable();
String currentClass = "";
PropertyDescriptor pd = null;
BeanVector bv = new BeanVector(this.size(),0,this);
bv.sortOnProperty(propertyName);
for(int i = 0; i < bv.size(); i++) {
if(!currentClass.equals(bv.elementAt(i).getClass().getName())) {
pd = (PropertyDescriptor)cache.get(bv.elementAt(i).getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(bv.elementAt(i).getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
cache.put(bv.elementAt(i).getClass().getName(),pd);
foundProperty = true;
}
}
}
}
if(hold == null) {
hold = pd.getReadMethod().invoke(bv.elementAt(i));
} else {
o = pd.getReadMethod().invoke(bv.elementAt(i));
if((o != null)&&o.equals(hold)) {
count++;
if(count > max) {
max = count;
index = this.indexOf(bv.elementAt(i));
}
} else {
count = 1;
}
hold = o;
}
}
return index;
}
/** Returns -1 or the the index of the next chunk after the current
* vector.
* @return -1 or the the index of the next chunk after the current vector
*/
public int getNextChunk() {
return this.nextChunk;
}
/**
* returns the number of chunks in the vector
* @return int value number of chunks
*/
public int getNumberOfChunks() {
return this.numberOfChunks;
}
/** Returns -1 or the the index of the previous chunk before the
* current vector.
* @return -1 or the the index of the previous chunk before the
* current vector
*/
public int getPreviousChunk() {
return this.previousChunk;
}
/**
* This method returns the sum of all values of a numerical
* property.
* @param propertyName String value of the property name to calculate.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
* @return sum of a numerical property
*/
public Number getSumOfProperty(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
double d = 0.0;
String currentClass = "";
PropertyDescriptor pd = null;
for(int i = 0; i < this.size(); i++) {
T o = this.elementAt(i);
if(!currentClass.equals(o.getClass().getName())) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty; pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
foundProperty = true;
}
}
}
if(o != null) {
Number n = (Number)pd.getReadMethod().invoke(o);
d += n.doubleValue();
}
}
return new Double(d);
}
/**
* Inserts the specified element at the specified position in this Vector.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
* @since 1.2
* @param index index at which the specified element is to be inserted.
* @param element element to be inserted.
*/
public void add(int index,T element) {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
super.add(index,element);
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
/**
* Appends the specified element to the end of this Vector.
*
* @param o element to be appended to this Vector.
* @return true (as per the general contract of Collection.add).
* @since 1.2
*/
public boolean add(T o) {
boolean retValue;
retValue = super.add(o);
if((this.indexPropertyName != null)&&(this.changes != null)) {
changes.fireIndexedPropertyChange(this.indexPropertyName,this.size() - 1,null,o);
}
return retValue;
}
/**
* Appends all of the elements in the specified Collection to the end of
* this Vector, in the order that they are returned by the specified
* Collection"s Iterator. The behavior of this operation is undefined if
* the specified Collection is modified while the operation is in progress.
* (This implies that the behavior of this call is undefined if the
* specified Collection is this Vector, and this Vector is nonempty.)
*
* @return <tt>true</tt> if this Vector changed as a result of the call.
* @since 1.2
* @param c elements to be inserted into this Vector.
*/
public boolean addAll(Collection<? extends T> c) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.addAll(c);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Inserts all of the elements in the specified Collection into this
* Vector at the specified position. Shifts the element currently at
* that position (if any) and any subsequent elements to the right
* (increases their indices). The new elements will appear in the Vector
* in the order that they are returned by the specified Collection"s
* iterator.
*
* @return <tt>true</tt> if this Vector changed as a result of the call.
* @since 1.2
* @param index index at which to insert first element
* from the specified collection.
* @param c elements to be inserted into this Vector.
*/
public boolean addAll(int index,Collection<? extends T> c) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.addAll(index,c);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Adds the specified component to the end of this vector,
* increasing its size by one. The capacity of this vector is
* increased if its size becomes greater than its capacity. <p>
*
* This method is identical in functionality to the add(Object) method
* (which is part of the List interface).
*
* @param obj the component to be added.
* @see #add(Object)
* @see List
*/
public void addElement(T obj) {
super.addElement(obj);
if((this.indexPropertyName != null)&&(this.changes != null)) {
changes.fireIndexedPropertyChange(this.indexPropertyName,this.size() - 1,null,obj);
}
}
/**
* Registers propertyChangeListeners to be fired when something changes in the Vector.
* Note, the whole vector is an "indexedProperty" name specified and parent delineated in
* the constructor.
* @param listener PropertyChangeListener to register
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
changes.addPropertyChangeListener(listener);
}
/**
* Registers propertyChangeListeners to be fired when something changes in the Vector.
* Note, the whole vector is an "indexedProperty" name specified and parent delineated in
* the constructor.
* @param property propteryName must match what the property name of this vector is or the listener will be ignored.
* @param listener the listener to register
*/
public void addPropertyChangeListener(String property,PropertyChangeListener listener) {
if((property != null)&&property.equals(this.indexPropertyName)) {
changes.addPropertyChangeListener(property,listener);
}
}
/**
* This method reverses the order of the vector.
*/
public synchronized void invert() {
BeanVector<T> temp = new BeanVector<T>(this);
for(int i = 0; i < this.size(); i++) {
this.setElementAt(temp.lastElement(),i);
temp.remove(temp.lastElement());
}
}
/**
* Removes the first occurrence of the specified element in this Vector
* If the Vector does not contain the element, it is unchanged. More
* formally, removes the element with the lowest index i such that
* <code>(o==null ? get(i)==null : o.equals(get(i)))</code> (if such
* an element exists).
*
* @param o element to be removed from this Vector, if present.
* @return true if the Vector contained the specified element.
* @since 1.2
*/
public boolean remove(Object o) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.remove(o);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Removes the element at the specified position in this Vector.
* shifts any subsequent elements to the left (subtracts one from their
* indices). Returns the element that was removed from the Vector.
*
* @return element that was removed
* @since 1.2
* @param index the index of the element to removed.
*/
public T remove(int index) {
T retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.remove(index);
if((retValue != null)&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Removes from this Vector all of its elements that are contained in the
* specified Collection.
*
* @return true if this Vector changed as a result of the call.
* @since 1.2
* @param c a collection of elements to be removed from the Vector
*/
public boolean removeAll(Collection<? > c) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.removeAll(c);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Removes all components from this vector and sets its size to zero.<p>
*
* This method is identical in functionality to the clear method
* (which is part of the List interface).
*
* @see #clear
* @see List
*/
public void removeAllElements() {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
super.removeAllElements();
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
/**
* Removes the first (lowest-indexed) occurrence of the argument
* from this vector. If the object is found in this vector, each
* component in the vector with an index greater or equal to the
* object"s index is shifted downward to have an index one smaller
* than the value it had previously.<p>
*
* This method is identical in functionality to the remove(Object)
* method (which is part of the List interface).
*
* @param obj the component to be removed.
* @return <code>true</code> if the argument was a component of this
* vector; <code>false</code> otherwise.
* @see List#remove(Object)
* @see List
*/
public boolean removeElement(Object obj) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.removeElement(obj);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Deletes the component at the specified index. Each component in
* this vector with an index greater or equal to the specified
* <code>index</code> is shifted downward to have an index one
* smaller than the value it had previously. The size of this vector
* is decreased by <tt>1</tt>.<p>
*
* The index must be a value greater than or equal to <code>0</code>
* and less than the current size of the vector. <p>
*
* This method is identical in functionality to the remove method
* (which is part of the List interface). Note that the remove method
* returns the old value that was stored at the specified position.
*
* @see #size()
* @see #remove(int)
* @see List
* @param index the index of the object to remove.
*/
public void removeElementAt(int index) {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
super.removeElementAt(index);
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
/**
* Removes propertyChangeListeners to be fired when something changes in the Vector.
* Note, the whole vector is an "indexedProperty" name specified and parent delineated in
* the constructor.
* @param listener listener to remove
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
changes.removePropertyChangeListener(listener);
}
/**
* Removes propertyChangeListeners to be fired when something changes in the Vector.
* Note, the whole vector is an "indexedProperty" name specified and parent delineated in
* the constructor.
* @param property must match the current property name for the vector or will be ignored
* @param listener listener to remove
*/
public void removePropertyChangeListener(String property,PropertyChangeListener listener) {
if((property != null)&&property.equals(this.indexPropertyName)) {
changes.removePropertyChangeListener(property,listener);
}
}
/**
* Resets the contents of the vector to the values provided.
* @param contents Array of object to replace the current contents with
*/
public synchronized void resetContents(T[] contents) {
if((this.indexPropertyName != null)&&(this.changes != null)) {
changes.firePropertyChange(this.indexPropertyName,this.toTypedArray(),contents);
}
this.removeAllElements();
for(T t : contents)
this.add(t);
}
/**
* Retains only the elements in this Vector that are contained in the
* specified Collection. In other words, removes from this Vector all
* of its elements that are not contained in the specified Collection.
*
* @return true if this Vector changed as a result of the call.
* @since 1.2
* @param c a collection of elements to be retained in this Vector
* (all other elements are removed)
*/
public boolean retainAll(Collection<? > c) {
boolean retValue;
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
retValue = super.retainAll(c);
if(retValue&&(old != null)) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
return retValue;
}
/**
* Replaces the element at the specified position in this Vector with the
* specified element.
*
* @return the element previously at the specified position.
* @since 1.2
* @param index index of element to replace.
* @param element element to be stored at the specified position.
*/
public T set(int index,T element) {
T retValue;
retValue = super.set(index,element);
if((this.indexPropertyName != null)&&(this.changes != null)) {
changes.fireIndexedPropertyChange(this.indexPropertyName,index,retValue,element);
}
return retValue;
}
/**
* performs a selection sort on all the beans in the Vector by PropertyName
*
* <p>You can use a mixture of bean classes as long as all the beans support
* the same property (getName() for instance), and all have the same return
* type.</p>
*
* <p>For optimal performance, it is recommended that if you have a
* mixed class set the you have them grouped with like classes together as this
* will minimize reflection inspections.</p>
* @param propertyName String value containing the property to sort
* on.
* @throws java.lang.IllegalAccessException Property was not accessible
* @throws java.beans.IntrospectionException Couldn"t introspect
* @throws java.lang.reflect.InvocationTargetException Is the proper signature getProperty() ?
*/
public void sortOnProperty(String propertyName) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
this.sortOnProperty(propertyName,true);
}
/**
* performs a selection sort on all the beans in the Vector by
* PropertyName
*
* <p>You can use a mixture of bean classes as long as all the beans
* support the same property (getName() for instance), and all have the
* same return type, or can be compareTo()ed each other.</p>
*
* <p>For optimal performance, it is recommended that if you have a
* mixed class set the you have them grouped with like classes together
* as this will minimize reflection inspections.</p>
* @param propertyName String value containing the property to sort on.
* @param ascending == sorts up if true, down if not.
* @throws java.lang.IllegalAccessException reflection exception
* @throws java.beans.IntrospectionException reflection exception
* @throws java.lang.reflect.InvocationTargetException reflection exception
*/
public synchronized void sortOnProperty(String propertyName,boolean ascending) throws java.lang.IllegalAccessException,java.beans.IntrospectionException,java.lang.reflect.InvocationTargetException {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
T temp = null;
String currentClass = "";
PropertyDescriptor pd = null;
Hashtable cache = new Hashtable();
for(int i = 0; i < (this.size() - 1); i++) {
for(int j = i + 1; j < this.size(); j++) {
T o1 = this.elementAt(i);
if(!currentClass.equals(o1.getClass().getName())) {
pd = (PropertyDescriptor)cache.get(o1.getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o1.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
cache.put(o1.getClass().getName(),pd);
foundProperty = true;
}
}
}
}
//System.out.println( "o1: "+o1+" "+pd);
//System.out.println( propertyName +" "+ (pd == null ));
Comparable oc1 = (Comparable)pd.getReadMethod().invoke(o1);
T o2 = this.elementAt(j);
if(!currentClass.equals(o2.getClass().getName())) {
pd = (PropertyDescriptor)cache.get(o2.getClass().getName());
if(pd == null) {
PropertyDescriptor[] pds = Introspector.getBeanInfo(o2.getClass()).getPropertyDescriptors();
boolean foundProperty = false;
for(int pdi = 0; (pdi < pds.length)&&!foundProperty;
pdi++) {
if(pds[pdi].getName().equals(propertyName)) {
pd = pds[pdi];
foundProperty = true;
}
}
}
}
Comparable oc2 = (Comparable)pd.getReadMethod().invoke(o2);
if(ascending) {
if((oc1 != oc2)&&((oc2 == null)||((oc1 != null)&&(oc2 != null)&&(oc2.rupareTo(oc1) < 0)))) { //swap
this.setElementAt(o2,i);
this.setElementAt(o1,j);
}
} else {
if((oc1 != oc2)&&((oc1 == null)||((oc1 != null)&&(oc2 != null)&&(oc1.rupareTo(oc2) < 0)))) { //swap
this.setElementAt(o2,i);
this.setElementAt(o1,j);
}
}
}
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
}
/**
* Returns an Array of the generic type associated with this Vector.
* @return Array representation of the current vector.
*/
public T[] toTypedArray() {
return (T[])this.toArray();
}
/**
* Removes from this List all of the elements whose index is between
* fromIndex, inclusive and toIndex, exclusive. Shifts any succeeding
* elements to the left (reduces their index).
* This call shortens the ArrayList by (toIndex - fromIndex) elements. (If
* toIndex==fromIndex, this operation has no effect.)
*
* @param fromIndex index of first element to be removed.
* @param toIndex index after last element to be removed.
*/
protected void removeRange(int fromIndex,int toIndex) {
T[] old = null;
if((this.indexPropertyName != null)&&(this.changes != null)) {
old = this.toTypedArray();
}
super.removeRange(fromIndex,toIndex);
if(old != null) {
changes.firePropertyChange(this.indexPropertyName,old,this.toTypedArray());
}
}
}
Bean Container
/*
Swing, Second Edition
by Matthew Robinson, Pavel Vorobiev
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.beans.*;
import java.lang.reflect.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
public class BeanContainer extends JFrame implements FocusListener{
protected File m_currentDir = new File(".");
protected Component m_activeBean;
protected String m_className = "clock.Clock";
protected JFileChooser m_chooser = new JFileChooser();
protected Hashtable m_editors = new Hashtable();
public BeanContainer() {
super("Simple Bean Container");
getContentPane().setLayout(new FlowLayout());
setSize(300, 300);
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
JMenuBar menuBar = createMenuBar();
setJMenuBar(menuBar);
WindowListener wndCloser = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
addWindowListener(wndCloser);
setVisible(true);
}
protected JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu mFile = new JMenu("File");
JMenuItem mItem = new JMenuItem("New...");
ActionListener lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Thread newthread = new Thread() {
public void run() {
String result = (String)JOptionPane.showInputDialog(
BeanContainer.this,
"Please enter class name to create a new bean",
"Input", JOptionPane.INFORMATION_MESSAGE, null,
null, m_className);
repaint();
if (result==null)
return;
try {
m_className = result;
Class cls = Class.forName(result);
Object obj = cls.newInstance();
if (obj instanceof Component) {
m_activeBean = (Component)obj;
m_activeBean.addFocusListener(
BeanContainer.this);
m_activeBean.requestFocus();
getContentPane().add(m_activeBean);
}
validate();
}
catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(
BeanContainer.this, "Error: "+ex.toString(),
"Warning", JOptionPane.WARNING_MESSAGE);
}
}
};
newthread.start();
}
};
mItem.addActionListener(lst);
mFile.add(mItem);
mItem = new JMenuItem("Load...");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Thread newthread = new Thread() {
public void run() {
m_chooser.setCurrentDirectory(m_currentDir);
m_chooser.setDialogTitle(
"Please select file with serialized bean");
int result = m_chooser.showOpenDialog(
BeanContainer.this);
repaint();
if (result != JFileChooser.APPROVE_OPTION)
return;
m_currentDir = m_chooser.getCurrentDirectory();
File fChoosen = m_chooser.getSelectedFile();
try {
FileInputStream fStream =
new FileInputStream(fChoosen);
ObjectInput stream =
new ObjectInputStream(fStream);
Object obj = stream.readObject();
if (obj instanceof Component) {
m_activeBean = (Component)obj;
m_activeBean.addFocusListener(
BeanContainer.this);
m_activeBean.requestFocus();
getContentPane().add(m_activeBean);
}
stream.close();
fStream.close();
validate();
}
catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(
BeanContainer.this, "Error: "+ex.toString(),
"Warning", JOptionPane.WARNING_MESSAGE);
}
repaint();
}
};
newthread.start();
}
};
mItem.addActionListener(lst);
mFile.add(mItem);
mItem = new JMenuItem("Save...");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Thread newthread = new Thread() {
public void run() {
if (m_activeBean == null)
return;
m_chooser.setDialogTitle(
"Please choose file to serialize bean");
m_chooser.setCurrentDirectory(m_currentDir);
int result = m_chooser.showSaveDialog(
BeanContainer.this);
repaint();
if (result != JFileChooser.APPROVE_OPTION)
return;
m_currentDir = m_chooser.getCurrentDirectory();
File fChoosen = m_chooser.getSelectedFile();
try {
FileOutputStream fStream =
new FileOutputStream(fChoosen);
ObjectOutput stream =
new ObjectOutputStream(fStream);
stream.writeObject(m_activeBean);
stream.close();
fStream.close();
}
catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(
BeanContainer.this, "Error: "+ex.toString(),
"Warning", JOptionPane.WARNING_MESSAGE);
}
}
};
newthread.start();
}
};
mItem.addActionListener(lst);
mFile.add(mItem);
mFile.addSeparator();
mItem = new JMenuItem("Exit");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
};
mItem.addActionListener(lst);
mFile.add(mItem);
menuBar.add(mFile);
JMenu mEdit = new JMenu("Edit");
mItem = new JMenuItem("Delete");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (m_activeBean == null)
return;
Object obj = m_editors.get(m_activeBean);
if (obj != null) {
BeanEditor editor = (BeanEditor)obj;
editor.dispose();
m_editors.remove(m_activeBean);
}
getContentPane().remove(m_activeBean);
m_activeBean = null;
validate();
repaint();
}
};
mItem.addActionListener(lst);
mEdit.add(mItem);
mItem = new JMenuItem("Properties...");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (m_activeBean == null)
return;
Object obj = m_editors.get(m_activeBean);
if (obj != null) {
BeanEditor editor = (BeanEditor)obj;
editor.setVisible(true);
editor.toFront();
}
else {
BeanEditor editor = new BeanEditor(m_activeBean);
m_editors.put(m_activeBean, editor);
}
}
};
mItem.addActionListener(lst);
mEdit.add(mItem);
menuBar.add(mEdit);
JMenu mLayout = new JMenu("Layout");
ButtonGroup group = new ButtonGroup();
mItem = new JRadioButtonMenuItem("FlowLayout");
mItem.setSelected(true);
lst = new ActionListener() {
public void actionPerformed(ActionEvent e){
getContentPane().setLayout(new FlowLayout());
validate();
repaint();
}
};
mItem.addActionListener(lst);
group.add(mItem);
mLayout.add(mItem);
mItem = new JRadioButtonMenuItem("GridLayout");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e){
int col = 3;
int row = (int)Math.ceil(getContentPane().
getComponentCount()/(double)col);
getContentPane().setLayout(new GridLayout(row, col, 10, 10));
validate();
repaint();
}
};
mItem.addActionListener(lst);
group.add(mItem);
mLayout.add(mItem);
mItem = new JRadioButtonMenuItem("BoxLayout - X");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
getContentPane().setLayout(new BoxLayout(
getContentPane(), BoxLayout.X_AXIS));
validate();
repaint();
}
};
mItem.addActionListener(lst);
group.add(mItem);
mLayout.add(mItem);
mItem = new JRadioButtonMenuItem("BoxLayout - Y");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
getContentPane().setLayout(new BoxLayout(
getContentPane(), BoxLayout.Y_AXIS));
validate();
repaint();
}
};
mItem.addActionListener(lst);
group.add(mItem);
mLayout.add(mItem);
mItem = new JRadioButtonMenuItem("DialogLayout");
lst = new ActionListener() {
public void actionPerformed(ActionEvent e) {
getContentPane().setLayout(new DialogLayout());
validate();
repaint();
}
};
mItem.addActionListener(lst);
group.add(mItem);
mLayout.add(mItem);
menuBar.add(mLayout);
return menuBar;
}
public void focusGained(FocusEvent e) {
m_activeBean = e.getComponent();
repaint();
}
public void focusLost(FocusEvent e) {}
// This is a heavyweight component so we override paint
// instead of paintComponent. super.paint(g) will
// paint all child components first, and then we
// simply draw over top of them.
public void paint(Graphics g) {
super.paint(g);
if (m_activeBean == null)
return;
Point pt = getLocationOnScreen();
Point pt1 = m_activeBean.getLocationOnScreen();
int x = pt1.x - pt.x - 2;
int y = pt1.y - pt.y - 2;
int w = m_activeBean.getWidth() + 2;
int h = m_activeBean.getHeight() + 2;
g.setColor(Color.black);
g.drawRect(x, y, w, h);
}
public static void main(String argv[]) {
new BeanContainer();
}
}
class BeanEditor extends JFrame implements PropertyChangeListener
{
protected Component m_bean;
protected JTable m_table;
protected PropertyTableData m_data;
public BeanEditor(Component bean) {
m_bean = bean;
m_bean.addPropertyChangeListener(this);
Point pt = m_bean.getLocationOnScreen();
setBounds(pt.x+50, pt.y+10, 400, 300);
getContentPane().setLayout(new BorderLayout());
m_data = new PropertyTableData(m_bean);
m_table = new JTable(m_data);
JScrollPane ps = new JScrollPane();
ps.getViewport().add(m_table);
getContentPane().add(ps, BorderLayout.CENTER);
setDefaultCloseOperation(HIDE_ON_CLOSE);
setVisible(true);
}
public void propertyChange(PropertyChangeEvent evt) {
m_data.setProperty(evt.getPropertyName(), evt.getNewValue());
}
class PropertyTableData extends AbstractTableModel
{
protected String[][] m_properties;
protected int m_numProps = 0;
protected Vector m_v;
public PropertyTableData(Component bean) {
try {
BeanInfo info = Introspector.getBeanInfo(
m_bean.getClass());
BeanDescriptor descr = info.getBeanDescriptor();
setTitle("Editing "+descr.getName());
PropertyDescriptor[] props = info.getPropertyDescriptors();
m_numProps = props.length;
m_v = new Vector(m_numProps);
for (int k=0; k<m_numProps; k++) {
String name = props[k].getDisplayName();
boolean added = false;
for (int i=0; i<m_v.size(); i++) {
String str = ((PropertyDescriptor)m_v.elementAt(i)).
getDisplayName();
if (name.rupareToIgnoreCase(str) < 0) {
m_v.insertElementAt(props[k], i);
added = true;
break;
}
}
if (!added)
m_v.addElement(props[k]);
}
m_properties = new String[m_numProps][2];
for (int k=0; k<m_numProps; k++) {
PropertyDescriptor prop =
(PropertyDescriptor)m_v.elementAt(k);
m_properties[k][0] = prop.getDisplayName();
Method mRead = prop.getReadMethod();
if (mRead != null &&
mRead.getParameterTypes().length == 0) {
Object value = mRead.invoke(m_bean, null);
m_properties[k][1] = objToString(value);
}
else
m_properties[k][1] = "error";
}
}
catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(
BeanEditor.this, "Error: "+ex.toString(),
"Warning", JOptionPane.WARNING_MESSAGE);
}
}
public void setProperty(String name, Object value) {
for (int k=0; k<m_numProps; k++)
if (name.equals(m_properties[k][0])) {
m_properties[k][1] = objToString(value);
m_table.tableChanged(new TableModelEvent(this, k));
m_table.repaint();
break;
}
}
public int getRowCount() { return m_numProps; }
public int getColumnCount() { return 2; }
public String getColumnName(int nCol) {
return nCol==0 ? "Property" : "Value";
}
public boolean isCellEditable(int nRow, int nCol) {
return (nCol==1);
}
public Object getValueAt(int nRow, int nCol) {
if (nRow < 0 || nRow>=getRowCount())
return "";
switch (nCol) {
case 0: return m_properties[nRow][0];
case 1: return m_properties[nRow][1];
}
return "";
}
public void setValueAt(Object value, int nRow, int nCol) {
if (nRow < 0 || nRow>=getRowCount())
return;
String str = value.toString();
PropertyDescriptor prop = (PropertyDescriptor)m_v.
elementAt(nRow);
Class cls = prop.getPropertyType();
Object obj = stringToObj(str, cls);
if (obj==null)
return; // can"t process
Method mWrite = prop.getWriteMethod();
if (mWrite == null || mWrite.getParameterTypes().length != 1)
return;
try {
mWrite.invoke(m_bean, new Object[]{ obj });
m_bean.getParent().doLayout();
m_bean.getParent().repaint();
m_bean.repaint();
}
catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(
BeanEditor.this, "Error: "+ex.toString(),
"Warning", JOptionPane.WARNING_MESSAGE);
}
m_properties[nRow][1] = str;
}
public String objToString(Object value) {
if (value==null)
return "null";
if (value instanceof Dimension) {
Dimension dim = (Dimension)value;
return ""+dim.width+","+dim.height;
}
else if (value instanceof Insets) {
Insets ins = (Insets)value;
return ""+ins.left+","+ins.top+","+ins.right+","+ins.bottom;
}
else if (value instanceof Rectangle) {
Rectangle rc = (Rectangle)value;
return ""+rc.x+","+rc.y+","+rc.width+","+rc.height;
}
else if (value instanceof Color) {
Color col = (Color)value;
return ""+col.getRed()+","+col.getGreen()+","+col.getBlue();
}
return value.toString();
}
public Object stringToObj(String str, Class cls) {
try {
if (str==null)
return null;
String name = cls.getName();
if (name.equals("java.lang.String"))
return str;
else if (name.equals("int"))
return new Integer(str);
else if (name.equals("long"))
return new Long(str);
else if (name.equals("float"))
return new Float(str);
else if (name.equals("double"))
return new Double(str);
else if (name.equals("boolean"))
return new Boolean(str);
else if (name.equals("java.awt.Dimension")) {
int[] i = strToInts(str);
return new Dimension(i[0], i[1]);
}
else if (name.equals("java.awt.Insets")) {
int[] i = strToInts(str);
return new Insets(i[0], i[1], i[2], i[3]);
}
else if (name.equals("java.awt.Rectangle")) {
int[] i = strToInts(str);
return new Rectangle(i[0], i[1], i[2], i[3]);
}
else if (name.equals("java.awt.Color")) {
int[] i = strToInts(str);
return new Color(i[0], i[1], i[2]);
}
return null; // not supported
}
catch(Exception ex) { return null; }
}
public int[] strToInts(String str) throws Exception {
int[] i = new int[4];
StringTokenizer tokenizer = new StringTokenizer(str, ",");
for (int k=0; k<i.length &&
tokenizer.hasMoreTokens(); k++)
i[k] = Integer.parseInt(tokenizer.nextToken());
return i;
}
}
}
/**
DialogLayout
*/
class DialogLayout implements LayoutManager {
protected int m_divider = -1;
protected int m_hGap = 10;
protected int m_vGap = 5;
public DialogLayout() {}
public DialogLayout(int hGap, int vGap)
{
m_hGap = hGap;
m_vGap = vGap;
}
public void addLayoutComponent(String name, Component comp) {}
public void removeLayoutComponent(Component comp) {}
public Dimension preferredLayoutSize(Container parent)
{
int divider = getDivider(parent);
int w = 0;
int h = 0;
for (int k=1 ; k<parent.getComponentCount(); k+=2)
{
Component comp = parent.getComponent(k);
Dimension d = comp.getPreferredSize();
w = Math.max(w, d.width);
h += d.height + m_vGap;
}
h -= m_vGap;
Insets insets = parent.getInsets();
return new Dimension(divider+w+insets.left+insets.right,
h+insets.top+insets.bottom);
}
public Dimension minimumLayoutSize(Container parent)
{
return preferredLayoutSize(parent);
}
public void layoutContainer(Container parent)
{
int divider = getDivider(parent);
Insets insets = parent.getInsets();
int w = parent.getWidth() - insets.left - insets.right - divider;
int x = insets.left;
int y = insets.top;
for (int k=1 ; k<parent.getComponentCount(); k+=2)
{
Component comp1 = parent.getComponent(k-1);
Component comp2 = parent.getComponent(k);
Dimension d = comp2.getPreferredSize();
comp1.setBounds(x, y, divider-m_hGap, d.height);
comp2.setBounds(x+divider, y, w, d.height);
y += d.height + m_vGap;
}
}
public int getHGap()
{
return m_hGap;
}
public int getVGap()
{
return m_vGap;
}
public void setDivider(int divider)
{
if (divider > 0)
m_divider = divider;
}
public int getDivider()
{
return m_divider;
}
protected int getDivider(Container parent)
{
if (m_divider > 0)
return m_divider;
int divider = 0;
for (int k=0 ; k<parent.getComponentCount(); k+=2)
{
Component comp = parent.getComponent(k);
Dimension d = comp.getPreferredSize();
divider = Math.max(divider, d.width);
}
divider += m_hGap;
return divider;
}
public String toString()
{
return getClass().getName() + "[hgap=" + m_hGap + ",vgap="
+ m_vGap + ",divider=" + m_divider + "]";
}
}
///////////File: Clock.java
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class Clock extends JButton
implements Customizer, Externalizable, Runnable
{
protected PropertyChangeSupport m_helper;
protected boolean m_digital = false;
protected Calendar m_calendar;
protected Dimension m_preffSize;
public Clock()
{
m_calendar = Calendar.getInstance();
m_helper = new PropertyChangeSupport(this);
Border br1 = new EtchedBorder(EtchedBorder.RAISED,
Color.white, new Color(128, 0, 0));
Border br2 = new MatteBorder(4, 4, 4, 4, Color.red);
setBorder(new CompoundBorder(br1, br2));
setBackground(Color.white);
setForeground(Color.black);
(new Thread(this)).start();
}
public void writeExternal(ObjectOutput out)
throws IOException
{
out.writeBoolean(m_digital);
out.writeObject(getBackground());
out.writeObject(getForeground());
out.writeObject(getPreferredSize());
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
setDigital(in.readBoolean());
setBackground((Color)in.readObject());
setForeground((Color)in.readObject());
setPreferredSize((Dimension)in.readObject());
}
public Dimension getPreferredSize()
{
if (m_preffSize != null)
return m_preffSize;
else
return new Dimension(50, 50);
}
public void setPreferredSize(Dimension preffSize)
{
m_preffSize = preffSize;
}
public Dimension getMinimumSize()
{
return getPreferredSize();
}
public Dimension getMaximumSize()
{
return getPreferredSize();
}
public void setDigital(boolean digital)
{
m_helper.firePropertyChange("digital",
new Boolean(m_digital),
new Boolean(digital));
m_digital = digital;
repaint();
}
public boolean getDigital()
{
return m_digital;
}
public void addPropertyChangeListener(
PropertyChangeListener lst)
{
if (m_helper != null)
m_helper.addPropertyChangeListener(lst);
}
public void removePropertyChangeListener(
PropertyChangeListener lst)
{
if (m_helper != null)
m_helper.removePropertyChangeListener(lst);
}
public void setObject(Object bean) {}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Color colorRetainer = g.getColor();
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight());
m_calendar.setTime(new Date()); // get current time
int hrs = m_calendar.get(Calendar.HOUR_OF_DAY);
int min = m_calendar.get(Calendar.MINUTE);
g.setColor(getForeground());
if (m_digital)
{
String time = ""+hrs+":"+min;
g.setFont(getFont());
FontMetrics fm = g.getFontMetrics();
int y = (getHeight() + fm.getAscent())/2;
int x = (getWidth() - fm.stringWidth(time))/2;
g.drawString(time, x, y);
}
else
{
int x = getWidth()/2;
int y = getHeight()/2;
int rh = getHeight()/4;
int rm = getHeight()/3;
double ah = ((double)hrs+min/60.0)/6.0*Math.PI;
double am = min/30.0*Math.PI;
g.drawLine(x, y, (int)(x+rh*Math.sin(ah)),
(int)(y-rh*Math.cos(ah)));
g.drawLine(x, y, (int)(x+rm*Math.sin(am)),
(int)(y-rm*Math.cos(am)));
}
g.setColor(colorRetainer);
}
public void run()
{
while (true)
{
repaint();
try
{
Thread.sleep(30*1000);
}
catch(InterruptedException ex) { break; }
}
}
}
Bean has a single property called property.
import java.io.Serializable;
public class BasicBean implements Serializable {
boolean property;
public BasicBean() {
}
public boolean getProperty() {
return property;
}
public boolean isProperty() {
return property;
}
public void setProperty(boolean newValue) {
property = newValue;
}
}
Bean Utility
/*
* StringUtil.java
*
* Created on May 7, 2004, 7:43 PM
*
* Copyright (C) 2004 Robert Cooper, Temple of the Screaming Penguin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.beans.*;
import java.lang.reflect.*;
/** This class contains some generic methods for working with String.
* @version $Rev: 87 $
* @author
*/
public class BeanUtility {
/** Creates a new instance of StringUtil */
private BeanUtility() { }
/** This method takes a JavaBean and generates a standard toString() type result for it.
* @param o JavaBean object to stringinate
* @return STRINGIATION! Stringingating the countryside. Stringinating all the peasants.
*/
public static String beanToString( Object o ){
StringBuffer result = new StringBuffer();
if(o == null)
return "--- null";
result.append( "--- begin");result.append( o.getClass().getName()); result.append(" hash: ");
result.append( o.hashCode() ); result.append( "\r\n");
try{
PropertyDescriptor[] pds = Introspector.getBeanInfo( o.getClass() ).getPropertyDescriptors();
for( int pdi = 0; pdi < pds.length; pdi ++ ){
try{
result.append( "Property: "+ pds[pdi].getName() + " Value: " + pds[pdi].getReadMethod().invoke( o ) );
} catch( IllegalAccessException iae ){
result.append( "Property: "+ pds[pdi].getName() + " (Illegal Access to Value) ");
}
catch( InvocationTargetException iae ){
result.append( "Property: "+ pds[pdi].getName() + " (InvocationTargetException) " + iae.toString() );
}
catch( Exception e ){
result.append( "Property: "+ pds[pdi].getName() +" (Other Exception )"+e.toString());
}
result.append( "\r\n");
}
} catch( IntrospectionException ie){
result.append( "Introspection Exception: " + ie.toString() ); result.append( "\r\n");
}
result.append( "--- end " ); result.append( o.getClass().getName()); result.append(" hash: ");
result.append( o.hashCode() ); result.append( "\n");
return result.toString();
}
/** This method takes 2 JavaBeans of the same type and copies the properties of one bean to the other.
* Any attempts that have an IllegalAccessException will be ignored. This will also NOT recurse into nested bean
* results. References to existing beanage will be includes. Try using .clone() for that stuff.
* @param from Source Bean
* @param to Desitnation Bean
*/
public static void copyBeanToBean( Object from, Object to ) throws InvocationTargetException, IntrospectionException{
PropertyDescriptor[] pds = Introspector.getBeanInfo( from.getClass() ).getPropertyDescriptors();
for( int i=0; i < pds.length; i++){
try{
if(pds[i].getName().equals("class")) continue;
Object[] value = {pds[i].getReadMethod().invoke(from) };
pds[i].getWriteMethod().invoke( to, value ) ;
} catch( IllegalAccessException iae ){
//Im just going to ignore any properties I don"t have access too.
}
}
}
public static String[] getPropertyNames(Object o) throws IntrospectionException {
PropertyDescriptor[] pds = Introspector.getBeanInfo( o.getClass() ).getPropertyDescriptors();
String[] propertyNames = new String[ pds.length];
for( int i=0; i< pds.length; i++){
propertyNames[i] = pds[i].getName();
}
return propertyNames;
}
public static Object getProperty( Object o, String propertyName ) throws Exception {
PropertyDescriptor[] pds = Introspector.getBeanInfo( o.getClass() ).getPropertyDescriptors();
for( int i=0; i< pds.length; i++){
if( pds[i].getName().equals(propertyName)){
return pds[i].getReadMethod().invoke( o ) ;
}
}
throw new Exception("Property not found.");
}
public static void setProperty( Object o, String propertyName, Object value ) throws Exception{
PropertyDescriptor[] pds = Introspector.getBeanInfo( o.getClass() ).getPropertyDescriptors();
for( int i=0; i< pds.length; i++){
if( pds[i].getName().equals(propertyName)){
pds[i].getWriteMethod().invoke( o, value );
return;
}
}
throw new Exception("Property not found.");
}
public static Class getPropertyType( Object o, String propertyName ) throws Exception{
PropertyDescriptor[] pds = Introspector.getBeanInfo( o.getClass() ).getPropertyDescriptors();
for( int i=0; i< pds.length; i++){
if( pds[i].getName().equals(propertyName)){
return pds[i].getPropertyType();
}
}
throw new Exception("Property not found.");
}
}
Convert a bean to XML persistence
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] args) throws Exception {
Item bean = new Item();
bean.setId(new Long(1));
bean.setItemName("a");
bean.setItemColour("Red");
bean.setItemQuantities(new Integer(100));
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(new FileOutputStream("Bean.xml")));
encoder.writeObject(bean);
encoder.close();
}
}
class Item {
private Long id;
private String itemName;
private String itemColour;
private Integer itemQuantities;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getItemColour() {
return itemColour;
}
public void setItemColour(String itemColour) {
this.itemColour = itemColour;
}
public Integer getItemQuantities() {
return itemQuantities;
}
public void setItemQuantities(Integer itemQuantities) {
this.itemQuantities = itemQuantities;
}
}
Convert an XML persistence to bean
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.Serializable;
public class Main {
public static void main(String[] argv) throws Exception {
XMLDecoder decoder = new XMLDecoder(new BufferedInputStream(new FileInputStream("Bean.xml")));
Bean bean = (Bean) decoder.readObject();
decoder.close();
System.out.println("ID = " + bean.getId());
}
}
class Bean implements Serializable {
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Here is our Bean.xml persistence file:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_02" class="java.beans.XMLDecoder">
<object class="org.username.example.bean.BeanToXML">
<void property="id">
<long>1</long>
</void>
</object>
</java>
Create an instance a Bean
import java.beans.Beans;
import java.io.Serializable;
public class Main implements Serializable {
private Long id;
private String name;
public Main() {
}
public static void main(String[] args) throws Exception {
Main bean = (Main) Beans.instantiate(ClassLoader.getSystemClassLoader(),
"Main");
System.out.println("The Bean = " + bean);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "[id=" + id + "; name=" + name + "]";
}
}
Deserializing a Bean from XML
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class Main {
public static void main(String[] argv) throws Exception {
XMLDecoder decoder = new XMLDecoder(new BufferedInputStream(
new FileInputStream("infilename.xml")));
MyClass o = (MyClass) decoder.readObject();
decoder.close();
int prop = o.getProp(); // 1
int[] props = o.getProps(); // [1, 2, 3]
}
}
class MyClass {
// The prop property
int i;
public int getProp() {
return i;
}
public void setProp(int i) {
this.i = i;
}
// The props property
int[] iarray = new int[0];
public int[] getProps() {
return iarray;
}
public void setProps(int[] iarray) {
this.iarray = iarray;
}
}
/*
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.0" class="java.beans.XMLDecoder">
<object class="MyClass">
<void property="prop">
<int>1</int>
</void>
<void property="props">
<array class="int" length="3">
<void index="0">
<int>1</int>
</void>
<void index="1">
<int>2</int>
</void>
<void index="2">
<int>3</int>
</void>
</array>
</void>
</object>
</java>
*/
Determine bean"s property type
import org.apache.rumons.beanutils.PropertyUtils;
public class Main {
public static void main(String[] args) throws Exception {
Recording recording = new Recording();
recording.setTitle("Magical Mystery Tour");
Class type = PropertyUtils.getPropertyType(recording, "title");
System.out.println("type = " + type.getName());
String value = (String) PropertyUtils.getProperty(recording, "title");
System.out.println("value = " + value);
}
}
Displaying the Current Directory in the Title of a JFileChooser Dialog
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import javax.swing.JFileChooser;
public class Main {
public static void main(String[] argv) {
final JFileChooser chooser = new JFileChooser();
File curDir = chooser.getCurrentDirectory();
chooser.setDialogTitle("" + curDir.getAbsolutePath());
chooser.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(evt.getPropertyName())) {
File curDir = chooser.getCurrentDirectory();
chooser.setDialogTitle("" + curDir.getAbsolutePath());
}
}
});
}
}
extends SimpleBeanInfo
/**
* FontSelectorBeanBeanInfo.java 1.00 97/08/09 Merlin Hughes
*
* Copyright (c) 1997 Merlin Hughes, All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* for commercial and non-commercial purposes and without fee is
* hereby granted provided that this copyright notice appears in
* all copies.
*
* http://prominence.ru/ ego@merlin.org
*/
import java.awt.Image;
import java.beans.SimpleBeanInfo;
public class FontSelectorBeanBeanInfo extends SimpleBeanInfo {
public Image getIcon(int iconKind) {
if (iconKind == ICON_COLOR_16x16) {
return loadImage("FontSelectorBeanIconColor16.gif");
} else {
return null;
}
}
}
Get a list of selected files
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import javax.swing.JFileChooser;
public class Main {
public static void main(String[] argv) throws Exception {
JFileChooser chooser = new JFileChooser();
chooser.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (JFileChooser.SELECTED_FILES_CHANGED_PROPERTY.equals(evt.getPropertyName())) {
JFileChooser chooser = (JFileChooser) evt.getSource();
File[] oldFiles = (File[]) evt.getOldValue();
File[] newFiles = (File[]) evt.getNewValue();
// Get list of selected files
File[] files = chooser.getSelectedFiles();
}
}
});
}
}
Get and set an Object type property
import java.beans.Expression;
import java.beans.Statement;
public class Main {
public static void main(String[] argv) throws Exception {
Object o = new MyBean();
// Get the value of prop1
Expression expr = new Expression(o, "getProp1", new Object[0]);
expr.execute();
String s = (String) expr.getValue();
// Set the value of prop1
Statement stmt = new Statement(o, "setProp1", new Object[] { "new string" });
stmt.execute();
}
}
class MyBean {
String prop1;
public String getProp1() {
return prop1;
}
public void setProp1(String s) {
prop1 = s;
}
int prop2;
public int getProp2() {
return prop2;
}
public void setProp2(int i) {
prop2 = i;
}
byte[] prop3;
public byte[] getProp3() {
return prop3;
}
public void setProp3(byte[] bytes) {
prop3 = bytes;
}
}
Get and set properties on a bean
/*
* The contents of this file are subject to the Sapient Public License
* Version 1.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://carbon.sf.net/License.html.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* The Original Code is The Carbon Component Framework.
*
* The Initial Developer of the Original Code is Sapient Corporation
*
* Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
*/
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.StringTokenizer;
/**
* <p>This class implements the ability to get and set properties on a
* bean. This included the concept of embedded properties that may
* be referenced like <code>Bean.property.property.property</code>.</p>
*
* Copyright 2002 Sapient
* @since carbon 1.0
* @author Greg Hinkle, January 2002
* @version $Revision: 1.11 $ ($Author: dvoet $)
*/
public final class BeanUtil {
/**
* String used to separate multiple properties inside of embedded
* beans.
*/
private static final String PROPERTY_SEPARATOR = ".";
/**
* An empty class array used for null parameter method reflection
*/
private static Class[] NO_PARAMETERS_ARRAY = new Class[] {
};
/**
* an empty object array used for null parameter method reflection
*/
private static Object[] NO_ARGUMENTS_ARRAY = new Object[] {
};
/**
* The constructor is private so that <tt>new</tt> cannot be used.
*/
private BeanUtil() {
}
/**
* Retreives a property descriptor object for a given property.
* <p>
* Uses the classes in <code>java.beans</code> to get back
* a descriptor for a property. Read-only and write-only
* properties will have a slower return time.
* </p>
*
* @param propertyName The programmatic name of the property
* @param beanClass The Class object for the target bean.
* For example sun.beans.OurButton.class.
* @return a PropertyDescriptor for a property that follows the
* standard Java naming conventions.
* @throws PropertyNotFoundException indicates that the property
* could not be found on the bean class.
*/
private static final PropertyDescriptor getPropertyDescriptor(
String propertyName,
Class beanClass) {
PropertyDescriptor resultPropertyDescriptor = null;
char[] pNameArray = propertyName.toCharArray();
pNameArray[0] = Character.toLowerCase(pNameArray[0]);
propertyName = new String(pNameArray);
try {
resultPropertyDescriptor =
new PropertyDescriptor(propertyName, beanClass);
} catch (IntrospectionException e1) {
// Read-only and write-only properties will throw this
// exception. The properties must be looked up using
// brute force.
// This will get the list of all properties and iterate
// through looking for one that matches the property
// name passed into the method.
try {
BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
PropertyDescriptor[] propertyDescriptors =
beanInfo.getPropertyDescriptors();
for (int i = 0; i < propertyDescriptors.length; i++) {
if (propertyDescriptors[i]
.getName()
.equals(propertyName)) {
// If the names match, this this describes the
// property being searched for. Break out of
// the iteration.
resultPropertyDescriptor = propertyDescriptors[i];
break;
}
}
} catch (IntrospectionException e2) {
e2.printStackTrace();
}
}
// If no property descriptor was found, then this bean does not
// have a property matching the name passed in.
if (resultPropertyDescriptor == null) {
System.out.println("resultPropertyDescriptor == null");
}
return resultPropertyDescriptor;
}
/**
* <p>Gets the specified attribute from the specified object. For example,
* <code>getObjectAttribute(o, "address.line1")</code> will return
* the result of calling <code>o.getAddress().getLine1()</code>.<p>
*
* <p>The attribute specified may contain as many levels as you like. If at
* any time a null reference is acquired by calling one of the successive
* getter methods, then the return value from this method is also null.</p>
*
* <p>When reading from a boolean property the underlying bean introspector
* first looks for an is<Property> read method, not finding one it will
* still look for a get<Property> read method. Not finding either, the
* property is considered write-only.</p>
*
* @param bean the bean to set the property on
* @param propertyNames the name of the propertie(s) to retrieve. If this is
* null or the empty string, then <code>bean</code> will be returned.
* @return the object value of the bean attribute
*
* @throws PropertyNotFoundException indicates the the given property
* could not be found on the bean
* @throws NoSuchMethodException Not thrown
* @throws InvocationTargetException if a specified getter method throws an
* exception.
* @throws IllegalAccessException if a getter method is
* not public or property is write-only.
*/
public static Object getObjectAttribute(Object bean, String propertyNames)
throws
NoSuchMethodException,
InvocationTargetException,
IllegalAccessException {
Object result = bean;
StringTokenizer propertyTokenizer =
new StringTokenizer(propertyNames, PROPERTY_SEPARATOR);
// Run through the tokens, calling get methods and
// replacing result with the new object each time.
// If the result equals null, then simply return null.
while (propertyTokenizer.hasMoreElements() && result != null) {
Class resultClass = result.getClass();
String currentPropertyName = propertyTokenizer.nextToken();
PropertyDescriptor propertyDescriptor =
getPropertyDescriptor(currentPropertyName, resultClass);
Method readMethod = propertyDescriptor.getReadMethod();
if (readMethod == null) {
throw new IllegalAccessException(
"User is attempting to "
+ "read from a property that has no read method. "
+ " This is likely a write-only bean property. Caused "
+ "by property ["
+ currentPropertyName
+ "] on class ["
+ resultClass
+ "]");
}
result = readMethod.invoke(result, NO_ARGUMENTS_ARRAY);
}
return result;
}
/**
* <p>Sets the specified attribute on the specified object. For example,
* <code>getObjectAttribute(o, "address.line1", value)</code> will call
* <code>o.getAddress().setLine1(value)</code>.<p>
*
* <p>The attribute specified may contain as many levels as you like. If at
* any time a null reference is acquired by calling one of the successive
* getter methods, then a <code>NullPointerException</code> is thrown.</p>
*
* @param bean the bean to call the getters on
* @param propertyNames the name of the attribute(s) to set. If this is
* null or the empty string, then an exception is thrown.
* @param value the value of the object to set on the bean property
*
* @throws PropertyNotFoundException indicates the the given property
* could not be found on the bean
* @throws IllegalArgumentException if the supplied parameter is not of
* a valid type
* @throws NoSuchMethodException never
* @throws IllegalAccessException if a getter or setter method is
* not public or property is read-only.
* @throws InvocationTargetException if a specified getter method throws an
* exception.
*/
public static void setObjectAttribute(
Object bean,
String propertyNames,
Object value)
throws
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException,
NoSuchMethodException {
Object result = bean;
String propertyName = propertyNames;
// Check if this has some embedded properties. If it does, use the
// getObjectAttribute to get the proper object to call this on.
int indexOfLastPropertySeparator =
propertyName.lastIndexOf(PROPERTY_SEPARATOR);
if (indexOfLastPropertySeparator >= 0) {
String embeddedProperties =
propertyName.substring(0, indexOfLastPropertySeparator);
// Grab the final property name after the last property separator
propertyName =
propertyName.substring(
indexOfLastPropertySeparator + PROPERTY_SEPARATOR.length());
result = getObjectAttribute(result, embeddedProperties);
}
Class resultClass = result.getClass();
PropertyDescriptor propertyDescriptor =
getPropertyDescriptor(propertyName, resultClass);
Method writeMethod = propertyDescriptor.getWriteMethod();
if (writeMethod == null) {
throw new IllegalAccessException(
"User is attempting to write "
+ "to a property that has no write method. This is likely "
+ "a read-only bean property. Caused by property ["
+ propertyName
+ "] on class ["
+ resultClass
+ "]");
}
writeMethod.invoke(result, new Object[] { value });
}
}
Get and set the value of a property in a bean using Expression and Statement
import java.beans.Expression;
import java.beans.Statement;
public class Main {
public static void main(String[] argv) throws Exception {
Object o = new MyBean();
// Get the value of prop1
Expression expr = new Expression(o, "getProp1", new Object[0]);
expr.execute();
String s = (String) expr.getValue();
// Set the value of prop1
Statement stmt = new Statement(o, "setProp1", new Object[] { "new string" });
stmt.execute();
}
}
class MyBean {
String prop1;
public String getProp1() {
return prop1;
}
public void setProp1(String s) {
prop1 = s;
}
int prop2;
public int getProp2() {
return prop2;
}
public void setProp2(int i) {
prop2 = i;
}
byte[] prop3;
public byte[] getProp3() {
return prop3;
}
public void setProp3(byte[] bytes) {
prop3 = bytes;
}
}
gets and sets an array type property
import java.beans.Expression;
import java.beans.Statement;
public class Main {
public static void main(String[] argv) throws Exception {
Object o = new MyBean();
Expression expr = new Expression(o, "getProp3", new Object[0]);
expr.execute();
byte[] bytes = (byte[]) expr.getValue();
Statement stmt = new Statement(o, "setProp3", new Object[] { new byte[] {
0x12, 0x23 } });
stmt.execute();
}
}
class MyBean {
String prop1;
public String getProp1() {
return prop1;
}
public void setProp1(String s) {
prop1 = s;
}
int prop2;
public int getProp2() {
return prop2;
}
public void setProp2(int i) {
prop2 = i;
}
byte[] prop3;
public byte[] getProp3() {
return prop3;
}
public void setProp3(byte[] bytes) {
prop3 = bytes;
}
}
gets and sets a primitive type property
import java.beans.Expression;
import java.beans.Statement;
public class Main {
public static void main(String[] argv) throws Exception {
Object o = new MyBean();
// Get the value of prop2
Expression expr = new Expression(o, "getProp2", new Object[0]);
expr.execute();
int i = ((Integer) expr.getValue()).intValue();
// Set the value of prop2
Statement stmt = new Statement(o, "setProp2", new Object[] { new Integer(123) });
stmt.execute();
}
}
class MyBean {
String prop1;
public String getProp1() {
return prop1;
}
public void setProp1(String s) {
prop1 = s;
}
int prop2;
public int getProp2() {
return prop2;
}
public void setProp2(int i) {
prop2 = i;
}
byte[] prop3;
public byte[] getProp3() {
return prop3;
}
public void setProp3(byte[] bytes) {
prop3 = bytes;
}
}
Getting and Setting a Property of a Bean
import java.beans.Expression;
import java.beans.Statement;
public class Main {
public static void main(String[] argv) throws Exception {
Object o = new MyBean();
// Get the value of prop1
Expression expr = new Expression(o, "getProp1", new Object[0]);
expr.execute();
String s = (String) expr.getValue();
// Set the value of prop1
Statement stmt = new Statement(o, "setProp1", new Object[] { "new string" });
stmt.execute();
}
}
class MyBean {
String prop1;
public String getProp1() {
return prop1;
}
public void setProp1(String s) {
prop1 = s;
}
int prop2;
public int getProp2() {
return prop2;
}
public void setProp2(int i) {
prop2 = i;
}
byte[] prop3;
public byte[] getProp3() {
return prop3;
}
public void setProp3(byte[] bytes) {
prop3 = bytes;
}
}
Implementing a Bound Property
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class MyBean {
PropertyChangeSupport pceListeners = new PropertyChangeSupport(this);
int myProperty;
public int getMyProperty() {
return myProperty;
}
public void setMyProperty(int newValue) {
int oldValue = myProperty;
myProperty = newValue;
pceListeners.firePropertyChange("myProperty", new Integer(oldValue),
new Integer(newValue));
}
public synchronized void addPropertyChangeListener(
PropertyChangeListener listener) {
pceListeners.addPropertyChangeListener(listener);
}
public synchronized void removePropertyChangeListener(
PropertyChangeListener listener) {
pceListeners.removePropertyChangeListener(listener);
}
}
Implementing a Constrained Property: fires a PropertyChangeEvent whenever its value is about to be changed.
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
public class MyBean {
VetoableChangeSupport vceListeners = new VetoableChangeSupport(this);
int myProperty;
public int getMyProperty() {
return myProperty;
}
public void setMyProperty(int newValue) throws PropertyVetoException {
try {
vceListeners.fireVetoableChange("myProperty", new Integer(myProperty),
new Integer(newValue));
myProperty = newValue;
} catch (PropertyVetoException e) {
throw e;
}
}
public synchronized void addVetoableChangeListener(
VetoableChangeListener listener) {
vceListeners.addVetoableChangeListener(listener);
}
public synchronized void removeVetoableChangeListener(
VetoableChangeListener listener) {
vceListeners.removeVetoableChangeListener(listener);
}
}
Instantiating a Bean
import java.beans.Beans;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
public class Main {
public static void main(String[] argv) throws Exception {
MyBean bean = (MyBean) Beans.instantiate(
ClassLoader.getSystemClassLoader(), "MyBean");
}
}
class MyBean {
VetoableChangeSupport vceListeners = new VetoableChangeSupport(this);
int myProperty;
public int getMyProperty() {
return myProperty;
}
public void setMyProperty(int newValue) throws PropertyVetoException {
try {
vceListeners.fireVetoableChange("myProperty", new Integer(myProperty),
new Integer(newValue));
myProperty = newValue;
} catch (PropertyVetoException e) {
throw e;
}
}
public synchronized void addVetoableChangeListener(
VetoableChangeListener listener) {
vceListeners.addVetoableChangeListener(listener);
}
public synchronized void removeVetoableChangeListener(
VetoableChangeListener listener) {
vceListeners.removeVetoableChangeListener(listener);
}
}
Introspecting a Bean
// : c14:BeanDumper.java
// Introspecting a Bean.
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.BeanInfo;
import java.beans.EventSetDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class BeanDumper extends JFrame {
private JTextField query = new JTextField(20);
private JTextArea results = new JTextArea();
public void print(String s) {
results.append(s + "\n");
}
public void dump(Class bean) {
results.setText("");
BeanInfo bi = null;
try {
bi = Introspector.getBeanInfo(bean, Object.class);
} catch (IntrospectionException e) {
print("Couldn"t introspect " + bean.getName());
return;
}
PropertyDescriptor[] properties = bi.getPropertyDescriptors();
for (int i = 0; i < properties.length; i++) {
Class p = properties[i].getPropertyType();
if (p == null)
continue;
print("Property type:\n " + p.getName() + "Property name:\n "
+ properties[i].getName());
Method readMethod = properties[i].getReadMethod();
if (readMethod != null)
print("Read method:\n " + readMethod);
Method writeMethod = properties[i].getWriteMethod();
if (writeMethod != null)
print("Write method:\n " + writeMethod);
print("====================");
}
print("Public methods:");
MethodDescriptor[] methods = bi.getMethodDescriptors();
for (int i = 0; i < methods.length; i++)
print(methods[i].getMethod().toString());
print("======================");
print("Event support:");
EventSetDescriptor[] events = bi.getEventSetDescriptors();
for (int i = 0; i < events.length; i++) {
print("Listener type:\n " + events[i].getListenerType().getName());
Method[] lm = events[i].getListenerMethods();
for (int j = 0; j < lm.length; j++)
print("Listener method:\n " + lm[j].getName());
MethodDescriptor[] lmd = events[i].getListenerMethodDescriptors();
for (int j = 0; j < lmd.length; j++)
print("Method descriptor:\n " + lmd[j].getMethod());
Method addListener = events[i].getAddListenerMethod();
print("Add Listener Method:\n " + addListener);
Method removeListener = events[i].getRemoveListenerMethod();
print("Remove Listener Method:\n " + removeListener);
print("====================");
}
}
class Dumper implements ActionListener {
public void actionPerformed(ActionEvent e) {
String name = query.getText();
Class c = null;
try {
c = Class.forName(name);
} catch (ClassNotFoundException ex) {
results.setText("Couldn"t find " + name);
return;
}
dump(c);
}
}
public BeanDumper() {
Container cp = getContentPane();
JPanel p = new JPanel();
p.setLayout(new FlowLayout());
p.add(new JLabel("Qualified bean name:"));
p.add(query);
cp.add(BorderLayout.NORTH, p);
cp.add(new JScrollPane(results));
Dumper dmpr = new Dumper();
query.addActionListener(dmpr);
query.setText("frogbean.Frog");
// Force evaluation
dmpr.actionPerformed(new ActionEvent(dmpr, 0, ""));
}
public static void main(String[] args) {
run(new BeanDumper(), 600, 500);
}
public static void run(JFrame frame, int width, int height) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(width, height);
frame.setVisible(true);
}
} ///:~
Is JavaBean Compliant Setter
import java.lang.reflect.Method;
public class Utils {
public static boolean isJavaBeanCompliantSetter (Method method)
{
if (method == null)
return false;
if (method.getReturnType() != Void.TYPE)
return false;
if (!method.getName().startsWith("set"))
return false;
if (method.getParameterTypes().length != 1)
return false;
return true;
}
}
JavaBean: BeanContextSupport
/*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
import java.beans.beancontext.BeanContextChildSupport;
import java.beans.beancontext.BeanContextSupport;
/**
* A test program that adds a bean to a beancontext, and reports on various
* aspects of the context"s membership state. This program also shows that a
* bean"s getBeanContext() method can be called to get a reference to its
* enclosing context.
*/
public class Example1 {
private static BeanContextSupport context = new BeanContextSupport(); // The
// BeanContext
private static BeanContextChildSupport bean = new BeanContextChildSupport(); // The
// JavaBean
public static void main(String[] args) {
report();
// Add the bean to the context
System.out.println("Adding bean to context...");
context.add(bean);
report();
}
private static void report() {
// Print out a report of the context"s membership state.
System.out.println("=============================================");
// Is the context empty?
System.out.println("Is the context empty? " + context.isEmpty());
// Has the context been set for the child bean?
boolean result = (bean.getBeanContext() != null);
System.out.println("Does the bean have a context yet? " + result);
// Number of children in the context
System.out.println("Number of children in the context: "
+ context.size());
// Is the specific bean a member of the context?
System.out.println("Is the bean a member of the context? "
+ context.contains(bean));
// Equality test
if (bean.getBeanContext() != null) {
boolean isEqual = (bean.getBeanContext() == context); // true means
// both
// references
// point to
// the same
// object
System.out.println("Contexts are the same? " + isEqual);
}
System.out.println("=============================================");
}
}
JavaBean: creates all of the objects, a tests the service capabilities
/*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
import java.beans.beancontext.BeanContextChildSupport;
import java.beans.beancontext.BeanContextServiceAvailableEvent;
import java.beans.beancontext.BeanContextServiceProvider;
import java.beans.beancontext.BeanContextServiceRevokedEvent;
import java.beans.beancontext.BeanContextServices;
import java.beans.beancontext.BeanContextServicesSupport;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Iterator;
import java.util.StringTokenizer;
/**
* A test program that creates all of the objects, a tests the service
* capabilities. Run this program from the command line using java
* DocumentTester
*/
public class DocumentTester {
public static void main(String[] args) {
BeanContextServicesSupport context = new BeanContextServicesSupport(); // a
// bean
// context
DocumentBean doc1 = new DocumentBean("Test.txt");
context.add(doc1);
context.addBeanContextServicesListener(doc1); // listen for new services
WordCountServiceProvider provider = new WordCountServiceProvider();
context.addService(WordCount.class, provider); // add the service to the
// context
}
}
/**
* A JavaBean that encapsulates a text file. When added to a bean context, this
* bean listens for a WordCount service to become available. When the service
* does become available, the DocumentBean requests an instance of the service.
* The service then counts the number of words in the file, and prints a report
* to standard output.
*/
final class DocumentBean extends BeanContextChildSupport {
private File document;
private BeanContextServices context;
/**
* Creates a new DocumentBean given the name of the file to read from.
*
* @param fileName
* the name of the file to read from
*/
public DocumentBean(String fileName) {
document = new File(fileName);
}
/**
* Called when this bean detects that a new service has been registered with
* its context.
*
* @param bcsae
* the BeanContextServiceAvailableEvent
*/
public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) {
System.out.println("[Detected a service being added to the context]");
// Get a reference to the context
BeanContextServices context = bcsae.getSourceAsBeanContextServices();
System.out.println("Is the context offering a WordCount service? "
+ context.hasService(WordCount.class));
// Use the service, if it"s available
if (context.hasService(WordCount.class)) {
System.out.println("Attempting to use the service...");
try {
WordCount service = (WordCount) context.getService(this, this,
WordCount.class, document, this);
System.out.println("Got the service!");
service.countWords();
} catch (Exception e) {
}
}
}
/**
* Called when this bean detects that a service has been revoked from the
* context.
*
* @param bcsre
* the BeanContextServiceRevokedEvent
*/
public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) {
System.out
.println("[Detected a service being revoked from the context]");
}
}
/**
* The WordCount service. Implementations of the countWords() method are
* provided by the WordCountServiceProvider class.
*/
interface WordCount {
/**
* Counts the number of words in the file.
*/
public abstract void countWords();
}
/**
* This class is the factory that delivers a word counting service. The 3
* methods defined in this class are the concrete implementations of the
* BeanContextServiceProvider interface. For this demonstration, the primary
* method of interest is getService(). The getService() methods returns a new
* WordCount instance. It is called by the bean context when a nested JavaBean
* requests the service.
*/
final class WordCountServiceProvider implements BeanContextServiceProvider {
public Object getService(BeanContextServices bcs, Object requestor,
Class serviceClass, Object serviceSelector) {
// For this demo, we know that the cast from serviceSelector
// to File will always work.
final File document = (File) serviceSelector;
/*
* Return an instance of the service. The service itself is the
* WordCount interface, which is implemented here using an anonymous
* inner class.
*/
return new WordCount() {
public void countWords() {
try {
// Create a Reader to the DocumentBean"s File
BufferedReader br = new BufferedReader(new FileReader(
document));
String line = null;
int wordCount = 0;
while ((line = br.readLine()) != null) {
StringTokenizer st = new StringTokenizer(line);
while (st.hasMoreTokens()) {
System.out.println("Word " + (++wordCount)
+ " is: " + st.nextToken());
}
}
System.out
.println("Total number of words in the document: "
+ wordCount);
System.out
.println("[WordCount service brought to you by WordCountServiceProvider]");
br.close();
} catch (Exception e) {
}
}
};
}
public void releaseService(BeanContextServices bcs, Object requestor,
Object service) {
// do nothing
}
public Iterator getCurrentServiceSelectors(BeanContextServices bcs,
Class serviceClass) {
return null; // do nothing
}
}
//file: Test.txt
/*
This text will be analyzed
by the WordCount
service.
*/
JavaBean: how to use the instantiateChild() convenience method to create a bean
/*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
import java.beans.beancontext.BeanContextChildSupport;
import java.beans.beancontext.BeanContextSupport;
import java.io.IOException;
/**
* An example of how to use the instantiateChild() convenience method to create
* a bean automatically nested into a bean context.
*/
public class Example3 {
public static void main(String[] args) {
BeanContextSupport context = new BeanContextSupport();
System.out.println("Number of children nested into the context: "
+ context.size());
BeanContextChildSupport child = null;
try {
child = (BeanContextChildSupport) context
.instantiateChild("java.beans.beancontext.BeanContextChildSupport");
} catch (IOException e) {
System.out.println("IOException occurred: " + e.getMessage());
} catch (ClassNotFoundException e) {
System.out.println("Class not found: " + e.getMessage());
}
System.out.println("Number of children nested into the context: "
+ context.size());
}
}
JavaBean: illustrate delivery of the BeanContextMembershipEvent
/*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
import java.beans.beancontext.BeanContextChildSupport;
import java.beans.beancontext.BeanContextMembershipEvent;
import java.beans.beancontext.BeanContextMembershipListener;
import java.beans.beancontext.BeanContextSupport;
/**
* A simple test program to illustrate delivery of the
* BeanContextMembershipEvent.
*/
public class MembershipTest {
public static void main(String[] args) {
BeanContextSupport context = new BeanContextSupport(); // the context
MyMembershipListener listener = new MyMembershipListener();
BeanContextChildSupport bean = new BeanContextChildSupport(); // a
// JavaBean
context.addBeanContextMembershipListener(listener); // now listening!
context.add(bean);
context.remove(bean);
}
}
/**
* A custom implementation of the BeanContextMembershipListener interface.
*/
class MyMembershipListener implements BeanContextMembershipListener {
public void childrenAdded(BeanContextMembershipEvent bcme) {
System.out.println("Another bean has been added to the context.");
}
public void childrenRemoved(BeanContextMembershipEvent bcme) {
System.out.println("A bean has been removed from the context.");
}
}
JavaBean: Test program that adds 100 beans to a context
/*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
import java.beans.beancontext.BeanContextChildSupport;
import java.beans.beancontext.BeanContextSupport;
/**
* Test program that adds 100 beans to a context, and calls size() to report the
* number of beans currently nested. Finally, this test calls toArray() to get
* references to all child beans.
*/
public class Example2 {
public static void main(String[] args) {
// A BeanContext
BeanContextSupport context = new BeanContextSupport();
// Many JavaBeans
BeanContextChildSupport[] beans = new BeanContextChildSupport[100];
System.out.println("Number of children in the context: "
+ context.size());
// Create the beans and add them to the context
for (int i = 0; i < beans.length; i++) {
beans[i] = new BeanContextSupport();
context.add(beans[i]);
}
System.out.println("Number of children in the context: "
+ context.size());
// Context now has 100 beans in it, get references to them all
Object[] children = context.toArray();
System.out.println("Number of objects retrieved from the context: "
+ children.length);
}
}
Listen for a constrained property change
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
public class Main {
private double interest;
private VetoableChangeSupport vcs = new VetoableChangeSupport(this);
public Main() {
vcs.addVetoableChangeListener(new VetoChangeListener());
}
public double getInterest() {
return interest;
}
public void setInterest(double interest) {
try {
vcs.fireVetoableChange("interest", new Double(this.interest), new Double(interest));
this.interest = interest;
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Main bean = new Main();
bean.setInterest(10.99);
bean.setInterest(15.99);
bean.setInterest(20.99);
}
}
class VetoChangeListener implements VetoableChangeListener {
public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
String eventName = evt.getPropertyName();
if (eventName.equalsIgnoreCase("interest")) {
double interest = ((Double) evt.getNewValue()).doubleValue();
if (interest > 20.00) {
throw new PropertyVetoException("Interest must be below 20.00", evt);
}
System.out.println("Interest applied = " + interest);
}
}
}
Listen for bean"s property change event
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
public class Main {
public static void main(String[] argv) throws Exception {
MyBean bean = new MyBean();
bean.setName("A");
bean.setName("B");
bean.setName("C");
}
}
class MyBean implements PropertyChangeListener, Serializable {
private Long id;
private String name;
private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public MyBean() {
pcs.addPropertyChangeListener(this);
}
public void propertyChange(PropertyChangeEvent evt) {
System.out.println("Name = " + evt.getPropertyName());
System.out.println("Old Value = " + evt.getOldValue());
System.out.println("New Value = " + evt.getNewValue());
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
String oldValue = this.name;
this.name = name;
pcs.firePropertyChange("name", oldValue, name);
}
}
Listening for a Property Change Event: A property change event is fired when a bound property is changed.
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class Main {
public static void main(String[] argv) throws Exception {
MyBean bean = new MyBean();
bean.addPropertyChangeListener(new MyPropertyChangeListener());
}
}
class MyPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
Object oldValue = evt.getOldValue();
Object newValue = evt.getNewValue();
}
}
class MyBean {
PropertyChangeSupport pceListeners = new PropertyChangeSupport(this);
int myProperty;
public int getMyProperty() {
return myProperty;
}
public void setMyProperty(int newValue) {
int oldValue = myProperty;
myProperty = newValue;
pceListeners.firePropertyChange("myProperty", new Integer(oldValue),
new Integer(newValue));
}
public synchronized void addPropertyChangeListener(
PropertyChangeListener listener) {
pceListeners.addPropertyChangeListener(listener);
}
public synchronized void removePropertyChangeListener(
PropertyChangeListener listener) {
pceListeners.removePropertyChangeListener(listener);
}
}
Listening for a Vetoable Property Change Event
// A vetoable property change event is fired when a constrained property is changed.
// A listener can veto the change by throwing PropertyVetoException and preventing the change.
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
public class Main {
public static void main(String[] argv) throws Exception {
MyBean bean = new MyBean();
bean.addVetoableChangeListener(new MyVetoableChangeListener());
}
}
class MyVetoableChangeListener implements VetoableChangeListener {
public void vetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException {
Object oldValue = evt.getOldValue();
Object newValue = evt.getNewValue();
boolean veto = false;
if (veto) {
throw new PropertyVetoException("the reason for the veto", evt);
}
}
}
class MyBean {
VetoableChangeSupport vceListeners = new VetoableChangeSupport(this);
int myProperty;
public int getMyProperty() {
return myProperty;
}
public void setMyProperty(int newValue) throws PropertyVetoException {
try {
vceListeners.fireVetoableChange("myProperty", new Integer(myProperty),
new Integer(newValue));
myProperty = newValue;
} catch (PropertyVetoException e) {
throw e;
}
}
public synchronized void addVetoableChangeListener(
VetoableChangeListener listener) {
vceListeners.addVetoableChangeListener(listener);
}
public synchronized void removeVetoableChangeListener(
VetoableChangeListener listener) {
vceListeners.removeVetoableChangeListener(listener);
}
}
Listening for Changes to the Current Directory in a JFileChooser Dialog
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import javax.swing.JFileChooser;
public class Main {
public static void main(String[] argv) throws Exception {
final JFileChooser chooser = new JFileChooser();
chooser.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(evt.getPropertyName())) {
JFileChooser chooser = (JFileChooser) evt.getSource();
File oldDir = (File) evt.getOldValue();
File newDir = (File) evt.getNewValue();
File curDir = chooser.getCurrentDirectory();
}
}
});
}
}
Listening for Changes to the Selected File in a JFileChooser Dialog
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import javax.swing.JFileChooser;
public class Main {
public static void main(String[] argv) throws Exception {
JFileChooser chooser = new JFileChooser();
chooser.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(evt.getPropertyName())) {
JFileChooser chooser = (JFileChooser) evt.getSource();
File oldFile = (File) evt.getOldValue();
File newFile = (File) evt.getNewValue();
File curFile = chooser.getSelectedFile();
}
}
});
}
}
Listing the Property Names of a Bean
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
public class Main {
public static void main(String[] argv) throws Exception {
BeanInfo bi = Introspector.getBeanInfo(MyBean.class);
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for (int i = 0; i < pds.length; i++) {
String propName = pds[i].getDisplayName();
System.out.println(propName);
}
}
}
class MyBean {
public String getProp1() {
return null;
}
public void setProp1(String s) {
}
public int getProp2() {
return 0;
}
public void setProp2(int i) {
}
public byte[] getPROP3() {
return null;
}
public void setPROP3(byte[] bytes) {
}
}
List property names of a Bean
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
public class Main {
public static void main(String[] argv) throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(Fruit.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
String propertyName = pd.getName();
System.out.println("propertyName = " + propertyName);
}
}
}
class Fruit implements Serializable {
private Long id;
private String name;
private double price;
public Fruit() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
Prevent bean"s property being serialized to XML
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] argv) throws Exception {
BeanInfo bi = Introspector.getBeanInfo(BeanToXmlTransient.class);
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for (int i = 0; i < pds.length; i++) {
PropertyDescriptor propertyDescriptor = pds[i];
if (propertyDescriptor.getName().equals("itemQuantities")) {
propertyDescriptor.setValue("transient", Boolean.TRUE);
}
}
BeanToXmlTransient bean = new BeanToXmlTransient();
bean.setId(new Long(1));
bean.setItemName("Item");
bean.setItemColour("Red");
bean.setItemQuantities(new Integer(100));
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(
"BeanTransient.xml")));
encoder.writeObject(bean);
encoder.close();
}
}
class BeanToXmlTransient {
private Long id;
private String itemName;
private String itemColour;
private Integer itemQuantities;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getItemColour() {
return itemColour;
}
public void setItemColour(String itemColour) {
this.itemColour = itemColour;
}
public Integer getItemQuantities() {
return itemQuantities;
}
public void setItemQuantities(Integer itemQuantities) {
this.itemQuantities = itemQuantities;
}
}
Preventing a Bean Property from Being Serialized to XML
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] argv) throws Exception {
MyClass o = new MyClass();
o.setProp(1);
o.setProps(new int[] { 1, 2, 3 });
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(
new FileOutputStream("outfilename.xml")));
encoder.writeObject(o);
encoder.close();
}
}
class MyClass {
int i;
public int getProp() {
return i;
}
public void setProp(int i) {
this.i = i;
}
int[] iarray = new int[0];
public int[] getProps() {
return iarray;
}
public void setProps(int[] iarray) {
this.iarray = iarray;
}
static {
try {
BeanInfo info = Introspector.getBeanInfo(MyClass.class);
PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
for (int i = 0; i < propertyDescriptors.length; ++i) {
PropertyDescriptor pd = propertyDescriptors[i];
if (pd.getName().equals("props")) {
pd.setValue("transient", Boolean.TRUE);
}
}
} catch (IntrospectionException e) {
}
}
}
PropertyTable
/*
* Copyright (c) 2000 David Flanagan. All rights reserved.
* This code is from the book Java Examples in a Nutshell, 2nd Edition.
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any non-commercial purpose.
* You may distribute it non-commercially as long as you retain this notice.
* For a commercial use license, or to purchase the book (recommended),
* visit http://www.davidflanagan.ru/javaexamples2.
*/
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.Arrays;
import java.util.ruparator;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
/**
* This class is a JTable subclass that displays a table of the JavaBeans
* properties of any specified class.
*/
public class PropertyTable extends JTable {
/** This main method allows the class to be demonstrated standalone */
public static void main(String[] args) {
// Specify the name of the class as a command-line argument
Class beanClass = null;
try {
// Use reflection to get the Class from the classname
beanClass = Class.forName("javax.swing.JLabel");
} catch (Exception e) { // Report errors
System.out.println("Can"t find specified class: " + e.getMessage());
System.out.println("Usage: java TableDemo <JavaBean class name>");
System.exit(0);
}
// Create a table to display the properties of the specified class
JTable table = new PropertyTable(beanClass);
// Then put the table in a scrolling window, put the scrolling
// window into a frame, and pop it all up on to the screen
JScrollPane scrollpane = new JScrollPane(table);
JFrame frame = new JFrame("Properties of JavaBean: ");
frame.getContentPane().add(scrollpane);
frame.setSize(500, 400);
frame.setVisible(true);
}
/**
* This constructor method specifies what data the table will display (the
* table model) and uses the TableColumnModel to customize the way that the
* table displays it. The hard work is done by the TableModel implementation
* below.
*/
public PropertyTable(Class beanClass) {
// Set the data model for this table
try {
setModel(new JavaBeanPropertyTableModel(beanClass));
} catch (IntrospectionException e) {
System.err.println("WARNING: can"t introspect: " + beanClass);
}
// Tweak the appearance of the table by manipulating its column model
TableColumnModel colmodel = getColumnModel();
// Set column widths
colmodel.getColumn(0).setPreferredWidth(125);
colmodel.getColumn(1).setPreferredWidth(200);
colmodel.getColumn(2).setPreferredWidth(75);
colmodel.getColumn(3).setPreferredWidth(50);
// Right justify the text in the first column
TableColumn namecol = colmodel.getColumn(0);
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setHorizontalAlignment(SwingConstants.RIGHT);
namecol.setCellRenderer(renderer);
}
/**
* This class implements TableModel and represents JavaBeans property data
* in a way that the JTable component can display. If you"ve got some type
* of tabular data to display, implement a TableModel class to describe that
* data, and the JTable component will be able to display it.
*/
static class JavaBeanPropertyTableModel extends AbstractTableModel {
PropertyDescriptor[] properties; // The properties to display
/**
* The constructor: use the JavaBeans introspector mechanism to get
* information about all the properties of a bean. Once we"ve got this
* information, the other methods will interpret it for JTable.
*/
public JavaBeanPropertyTableModel(Class beanClass)
throws java.beans.IntrospectionException {
// Use the introspector class to get "bean info" about the class.
BeanInfo beaninfo = Introspector.getBeanInfo(beanClass);
// Get the property descriptors from that BeanInfo class
properties = beaninfo.getPropertyDescriptors();
// Now do a case-insensitive sort by property name
// The anonymous Comparator implementation specifies how to
// sort PropertyDescriptor objects by name
Arrays.sort(properties, new Comparator() {
public int compare(Object p, Object q) {
PropertyDescriptor a = (PropertyDescriptor) p;
PropertyDescriptor b = (PropertyDescriptor) q;
return a.getName().rupareToIgnoreCase(b.getName());
}
public boolean equals(Object o) {
return o == this;
}
});
}
// These are the names of the columns represented by this TableModel
static final String[] columnNames = new String[] { "Name", "Type",
"Access", "Bound" };
// These are the types of the columns represented by this TableModel
static final Class[] columnTypes = new Class[] { String.class,
Class.class, String.class, Boolean.class };
// These simple methods return basic information about the table
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return properties.length;
}
public String getColumnName(int column) {
return columnNames[column];
}
public Class getColumnClass(int column) {
return columnTypes[column];
}
/**
* This method returns the value that appears at the specified row and
* column of the table
*/
public Object getValueAt(int row, int column) {
PropertyDescriptor prop = properties[row];
switch (column) {
case 0:
return prop.getName();
case 1:
return prop.getPropertyType();
case 2:
return getAccessType(prop);
case 3:
return new Boolean(prop.isBound());
default:
return null;
}
}
// A helper method called from getValueAt() above
String getAccessType(PropertyDescriptor prop) {
java.lang.reflect.Method reader = prop.getReadMethod();
java.lang.reflect.Method writer = prop.getWriteMethod();
if ((reader != null) && (writer != null))
return "Read/Write";
else if (reader != null)
return "Read-Only";
else if (writer != null)
return "Write-Only";
else
return "No Access"; // should never happen
}
}
}
Read bean"s property value
import java.lang.reflect.InvocationTargetException;
import org.apache.rumons.beanutils.PropertyUtils;
public class Main {
public static void main(String[] args) {
MyClass track = new MyClass();
track.setTitle("this is a test");
String title = (String) PropertyUtils.getSimpleProperty(track, "title");
System.out.println("Title = " + title);
}
}
class MyClass {
private Integer id;
private String title;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
Saving and restoring the state of a pretend CAD system
// : c12:CADState.java
// Saving and restoring the state of a pretend CAD system.
// {Clean: CADState.out}
//package c12;
// From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002
// www.BruceEckel.ru. See copyright notice in CopyRight.txt.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
abstract class Shape implements Serializable {
public static final int RED = 1, BLUE = 2, GREEN = 3;
private int xPos, yPos, dimension;
private static Random r = new Random();
private static int counter = 0;
public abstract void setColor(int newColor);
public abstract int getColor();
public Shape(int xVal, int yVal, int dim) {
xPos = xVal;
yPos = yVal;
dimension = dim;
}
public String toString() {
return getClass() + "color[" + getColor() + "] xPos[" + xPos
+ "] yPos[" + yPos + "] dim[" + dimension + "]\n";
}
public static Shape randomFactory() {
int xVal = r.nextInt(100);
int yVal = r.nextInt(100);
int dim = r.nextInt(100);
switch (counter++ % 3) {
default:
case 0:
return new Circle(xVal, yVal, dim);
case 1:
return new Square(xVal, yVal, dim);
case 2:
return new Line(xVal, yVal, dim);
}
}
}
class Circle extends Shape {
private static int color = RED;
public Circle(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}
class Square extends Shape {
private static int color;
public Square(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
color = RED;
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}
class Line extends Shape {
private static int color = RED;
public static void serializeStaticState(ObjectOutputStream os)
throws IOException {
os.writeInt(color);
}
public static void deserializeStaticState(ObjectInputStream os)
throws IOException {
color = os.readInt();
}
public Line(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}
public class CADState {
public static void main(String[] args) throws Exception {
List shapeTypes, shapes;
if (args.length == 0) {
shapeTypes = new ArrayList();
shapes = new ArrayList();
// Add references to the class objects:
shapeTypes.add(Circle.class);
shapeTypes.add(Square.class);
shapeTypes.add(Line.class);
// Make some shapes:
for (int i = 0; i < 10; i++)
shapes.add(Shape.randomFactory());
// Set all the static colors to GREEN:
for (int i = 0; i < 10; i++)
((Shape) shapes.get(i)).setColor(Shape.GREEN);
// Save the state vector:
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("CADState.out"));
out.writeObject(shapeTypes);
Line.serializeStaticState(out);
out.writeObject(shapes);
} else { // There"s a command-line argument
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
args[0]));
// Read in the same order they were written:
shapeTypes = (List) in.readObject();
Line.deserializeStaticState(in);
shapes = (List) in.readObject();
}
// Display the shapes:
System.out.println(shapes);
}
} ///:~
Serializing a Bean to XML: XMLEncoder only persists the value of public properties.
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] argv) throws Exception {
MyClass o = new MyClass();
o.setProp(1);
o.setProps(new int[] { 1, 2, 3 });
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(
new FileOutputStream("outfilename.xml")));
encoder.writeObject(o);
encoder.close();
}
}
class MyClass {
// The prop property
int i;
public int getProp() {
return i;
}
public void setProp(int i) {
this.i = i;
}
// The props property
int[] iarray = new int[0];
public int[] getProps() {
return iarray;
}
public void setProps(int[] iarray) {
this.iarray = iarray;
}
}
Serializing an Immutable Bean Property to XML
import java.beans.DefaultPersistenceDelegate;
import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] argv) throws Exception {
MyClass o = new MyClass(123);
XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(
new FileOutputStream("outfilename.xml")));
String[] propertyNames = new String[] { "prop" };
encoder.setPersistenceDelegate(MyClass.class,
new DefaultPersistenceDelegate(propertyNames));
encoder.writeObject(o);
encoder.close();
}
}
class MyClass {
int prop;
public MyClass(int prop) {
this.prop = prop;
}
public int getProp() {
return prop;
}
}
Setting an Accessory Component in a JFileChooser Dialog
import java.awt.Dimension;
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
public class Main {
public static void main(String[] argv) {
JFileChooser chooser = new JFileChooser();
chooser.setAccessory(new MyAccessory(chooser));
chooser.showOpenDialog(null);
}
}
class MyAccessory extends JComponent implements PropertyChangeListener {
public MyAccessory(JFileChooser chooser) {
chooser.addPropertyChangeListener(this);
setPreferredSize(new Dimension(50, 50));
}
public void propertyChange(PropertyChangeEvent evt) {
if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(evt.getPropertyName())) {
JFileChooser chooser = (JFileChooser) evt.getSource();
// Get the new selected file
File newFile = (File) evt.getNewValue();
repaint();
}
}
public void paint(Graphics g) {
// Paint a preview of the selected file
}
}