📄 propertyutils.java
字号:
package jaction.utility;
import java.beans.BeanInfo;
import java.beans.IndexedPropertyDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Utility methods for using Java Reflection APIs to facilitate generic
* property getter and setter operations on Java objects. Much of this
* code was originally included in <code>BeanUtils</code>, but has been
* separated because of the volume of code involved.
* <p>
* In general, the objects that are examined and modified using these
* methods are expected to conform to the property getter and setter method
* naming conventions described in the JavaBeans Specification (Version 1.0.1).
* No data type conversions are performed, and there are no usage of any
* <code>PropertyEditor</code> classes that have been registered, although
* a convenient way to access the registered classes themselves is included.
* <p>
* For the purposes of this class, three formats for referencing a particular
* property value of a bean are defined, with the layout of an identifying
* String in parentheses:
* <ul>
* <li><strong>Simple (<code>name</code>)</strong> - The specified
* <code>name</code> identifies an individual property of a particular
* JavaBean. The name of the actual getter or setter method to be used
* is determined using standard JavaBeans instrospection, so that (unless
* overridden by a <code>BeanInfo</code> class, a property named "xyz"
* will have a getter method named <code>getXyz()</code> or (for boolean
* properties only) <code>isXyz()</code>, and a setter method named
* <code>setXyz()</code>.</li>
* <li><strong>Nested (<code>name1.name2.name3</code>)</strong> The first
* name element is used to select a property getter, as for simple
* references above. The object returned for this property is then
* consulted, using the same approach, for a property getter for a
* property named <code>name2</code>, and so on. The property value that
* is ultimately retrieved or modified is the one identified by the
* last name element.</li>
* <li><strong>Indexed (<code>name[index]</code>)</strong> - The underlying
* property value is assumed to be an array, or this JavaBean is assumed
* to have indexed property getter and setter methods. The appropriate
* (zero-relative) entry in the array is selected.</li>
* <li><strong>Combined (<code>name1.name2[index].name3</strong> - Various
* forms combining nested and indexed references are also supported.</li>
* </ul>
*
* @deprecated At some point after Struts 1.0 final, will be replaced by
* an equivalent class in the Jakarta Commons Beanutils package.
*
* @author Craig R. McClanahan
* @author Ralph Schaer
* @author Chris Audley
* @version $Revision: 1.14 $ $Date: 2001/05/20 01:18:28 $
*/
public class PropertyUtils {
// ----------------------------------------------------- Manifest Constants
/**
* The delimiter that preceeds the zero-relative subscript for an
* indexed reference.
*/
public static final char INDEXED_DELIM = '[';
/**
* The delimiter that follows the zero-relative subscript for an
* indexed reference.
*/
public static final char INDEXED_DELIM2 = ']';
/**
* The delimiter that separates the components of a nested reference.
*/
public static final char NESTED_DELIM = '.';
// ------------------------------------------------------- Static Variables
/**
* The debugging detail level for this component.
*/
private static int debug = 0;
public static int getDebug() {
return (debug);
}
public static void setDebug(int newDebug) {
debug = newDebug;
}
/**
* The cache of PropertyDescriptor arrays for beans we have already
* introspected, keyed by the fully qualified class name of this object.
*/
private static FastHashMap descriptorsCache = null;
static {
descriptorsCache = new FastHashMap();
descriptorsCache.setFast(true);
}
// --------------------------------------------------------- Public Methods
/**
* Copy property values from the "origin" bean to the "destination" bean
* for all cases where the property names are the same (even though the
* actual getter and setter methods might have been customized via
* <code>BeanInfo</code> classes). No conversions are performed on the
* actual property values -- it is assumed that the values retrieved from
* the origin bean are assignment-compatible with the types expected by
* the destination bean.
*
* @param dest Destination bean whose properties are modified
* @param orig Origin bean whose properties are retrieved
*
* @exception IllegalAccessException if the caller does not have
* access to the property accessor method
* @exception IllegalArgumentException if the <code>dest</code> or
* <code>orig</code> argument is null
* @exception InvocationTargetException if the property accessor method
* throws an exception
* @exception NoSuchMethodException if an accessor method for this
* propety cannot be found
*/
public static void copyProperties(Object dest, Object orig)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
if (dest == null)
throw new IllegalArgumentException
("No destination bean specified");
if (orig == null)
throw new IllegalArgumentException("No origin bean specified");
PropertyDescriptor origDescriptors[] = getPropertyDescriptors(orig);
for (int i = 0; i < origDescriptors.length; i++) {
String name = origDescriptors[i].getName();
if (getPropertyDescriptor(dest, name) != null) {
Object value = getSimpleProperty(orig, name);
try {
setSimpleProperty(dest, name, value);
} catch (NoSuchMethodException e) {
; // Skip non-matching property
}
}
}
}
/**
* Return the entire set of properties for which the specified bean
* provides a read method. This map contains the unconverted property
* values for all properties for which a read method is provided
* (i.e. where the <code>getReadMethod()</code> returns non-null).
*
* @param bean Bean whose properties are to be extracted
*
* @exception IllegalAccessException if the caller does not have
* access to the property accessor method
* @exception IllegalArgumentException if <code>bean</code> is null
* @exception InvocationTargetException if the property accessor method
* throws an exception
* @exception NoSuchMethodException if an accessor method for this
* propety cannot be found
*/
public static Map describe(Object bean)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
if (bean == null)
throw new IllegalArgumentException("No bean specified");
PropertyDescriptor descriptors[] =
PropertyUtils.getPropertyDescriptors(bean);
Map description = new HashMap(descriptors.length);
for (int i = 0; i < descriptors.length; i++) {
String name = descriptors[i].getName();
if (descriptors[i].getReadMethod() != null)
description.put(name, getProperty(bean, name));
}
return (description);
}
/**
* Return the value of the specified indexed property of the specified
* bean, with no type conversions. The zero-relative index of the
* required value must be included (in square brackets) as a suffix to
* the property name, or <code>IllegalArgumentException</code> will be
* thrown.
*
* @param bean Bean whose property is to be extracted
* @param name <code>propertyname[index]</code> of the property value
* to be extracted
*
* @exception IllegalAccessException if the caller does not have
* access to the property accessor method
* @exception IllegalArgumentException if <code>bean</code> or
* <code>name</code> is null
* @exception InvocationTargetException if the property accessor method
* throws an exception
* @exception NoSuchMethodException if an accessor method for this
* propety cannot be found
*/
public static Object getIndexedProperty(Object bean, String name)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
if (bean == null)
throw new IllegalArgumentException("No bean specified");
if (name == null)
throw new IllegalArgumentException("No name specified");
// Identify the index of the requested individual property
int delim = name.indexOf(INDEXED_DELIM);
int delim2 = name.indexOf(INDEXED_DELIM2);
if ((delim < 0) || (delim2 <= delim))
throw new IllegalArgumentException("Invalid indexed property '" +
name + "'");
int index = -1;
try {
String subscript = name.substring(delim + 1, delim2);
index = Integer.parseInt(subscript);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid indexed property '" +
name + "'");
}
name = name.substring(0, delim);
// Request the specified indexed property value
return (getIndexedProperty(bean, name, index));
}
/**
* Return the value of the specified indexed property of the specified
* bean, with no type conversions.
*
* @param bean Bean whose property is to be extracted
* @param name Simple property name of the property value to be extracted
* @param index Index of the property value to be extracted
*
* @exception IllegalAccessException if the caller does not have
* access to the property accessor method
* @exception IllegalArgumentException if <code>bean</code> or
* <code>name</code> is null
* @exception InvocationTargetException if the property accessor method
* throws an exception
* @exception NoSuchMethodException if an accessor method for this
* propety cannot be found
*/
public static Object getIndexedProperty(Object bean,
String name, int index)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
if (bean == null)
throw new IllegalArgumentException("No bean specified");
if (name == null)
throw new IllegalArgumentException("No name specified");
// Retrieve the property descriptor for the specified property
PropertyDescriptor descriptor =
getPropertyDescriptor(bean, name);
if (descriptor == null)
throw new NoSuchMethodException("Unknown property '" +
name + "'");
// Call the indexed getter method if there is one
if (descriptor instanceof IndexedPropertyDescriptor) {
Method readMethod = ((IndexedPropertyDescriptor) descriptor).
getIndexedReadMethod();
if (readMethod != null) {
Object subscript[] = new Object[1];
subscript[0] = new Integer(index);
return (readMethod.invoke(bean, subscript));
}
}
// Otherwise, the underlying property must be an array
Method readMethod = getReadMethod(descriptor);
if (readMethod == null)
throw new NoSuchMethodException("Property '" + name +
"' has no getter method");
// Call the property getter and return the value
Object value = readMethod.invoke(bean, new Object[0]);
if (!value.getClass().isArray())
throw new IllegalArgumentException("Property '" + name +
"' is not indexed");
return (Array.get(value, index));
}
/**
* Return the value of the (possibly nested) property of the specified
* name, for the specified bean, with no type conversions.
*
* @param bean Bean whose property is to be extracted
* @param name Possibly nested name of the property to be extracted
*
* @exception IllegalAccessException if the caller does not have
* access to the property accessor method
* @exception IllegalArgumentException if <code>bean</code> or
* <code>name</code> is null
* @exception IllegalArgumentException if a nested reference to a
* property returns null
* @exception InvocationTargetException if the property accessor method
* throws an exception
* @exception NoSuchMethodException if an accessor method for this
* propety cannot be found
*/
public static Object getNestedProperty(Object bean, String name)
throws IllegalAccessException, InvocationTargetException,
NoSuchMethodException {
if (bean == null)
throw new IllegalArgumentException("No bean specified");
if (name == null)
throw new IllegalArgumentException("No name specified");
while (true) {
int delim = name.indexOf(NESTED_DELIM);
if (delim < 0)
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -