Introspectorpublic class Introspector extends Object The Introspector class provides a standard way for tools to learn about
the properties, events, and methods supported by a target Java Bean.
For each of those three kinds of information, the Introspector will
separately analyze the bean's class and superclasses looking for
either explicit or implicit information and use that information to
build a BeanInfo object that comprehensively describes the target bean.
For each class "Foo", explicit information may be available if there exists
a corresponding "FooBeanInfo" class that provides a non-null value when
queried for the information. We first look for the BeanInfo class by
taking the full package-qualified name of the target bean class and
appending "BeanInfo" to form a new class name. If this fails, then
we take the final classname component of this name, and look for that
class in each of the packages specified in the BeanInfo package search
path.
Thus for a class such as "sun.xyz.OurButton" we would first look for a
BeanInfo class called "sun.xyz.OurButtonBeanInfo" and if that failed we'd
look in each package in the BeanInfo search path for an OurButtonBeanInfo
class. With the default search path, this would mean looking for
"sun.beans.infos.OurButtonBeanInfo".
If a class provides explicit BeanInfo about itself then we add that to
the BeanInfo information we obtained from analyzing any derived classes,
but we regard the explicit information as being definitive for the current
class and its base classes, and do not proceed any further up the superclass
chain.
If we don't find explicit BeanInfo on a class, we use low-level
reflection to study the methods of the class and apply standard design
patterns to identify property accessors, event sources, or public
methods. We then proceed to analyze the class's superclass and add
in the information from it (and possibly on up the superclass chain).
Because the Introspector caches BeanInfo classes for better performance,
take care if you use it in an application that uses
multiple class loaders.
In general, when you destroy a ClassLoader
that has been used to introspect classes,
you should use the
{@link #flushCaches Introspector.flushCaches }
or
{@link #flushFromCaches Introspector.flushFromCaches } method
to flush all of the introspected classes out of the cache.
For more information about introspection and design patterns, please
consult the
JavaBeans specification. |
Fields Summary |
---|
public static final int | USE_ALL_BEANINFO | public static final int | IGNORE_IMMEDIATE_BEANINFO | public static final int | IGNORE_ALL_BEANINFO | private static Map | declaredMethodCache | private static Map | beanInfoCache | private Class | beanClass | private BeanInfo | explicitBeanInfo | private BeanInfo | superBeanInfo | private BeanInfo[] | additionalBeanInfo | private boolean | propertyChangeSource | private static Class | eventListenerType | private String | defaultEventName | private String | defaultPropertyName | private int | defaultEventIndex | private int | defaultPropertyIndex | private Map | methods | private Map | properties | private Map | events | private static final String | DEFAULT_INFO_PATH | private static String[] | searchPath | private static final EventSetDescriptor[] | EMPTY_EVENTSETDESCRIPTORS | private static final String | ADD_PREFIX | private static final String | REMOVE_PREFIX | private static final String | GET_PREFIX | private static final String | SET_PREFIX | private static final String | IS_PREFIX | private static final String | BEANINFO_SUFFIX | private HashMap | pdStore |
Constructors Summary |
---|
private Introspector(Class beanClass, Class stopClass, int flags)
this.beanClass = beanClass;
// Check stopClass is a superClass of startClass.
if (stopClass != null) {
boolean isSuper = false;
for (Class c = beanClass.getSuperclass(); c != null; c = c.getSuperclass()) {
if (c == stopClass) {
isSuper = true;
}
}
if (!isSuper) {
throw new IntrospectionException(stopClass.getName() + " not superclass of " +
beanClass.getName());
}
}
if (flags == USE_ALL_BEANINFO) {
explicitBeanInfo = findExplicitBeanInfo(beanClass);
}
Class superClass = beanClass.getSuperclass();
if (superClass != stopClass) {
int newFlags = flags;
if (newFlags == IGNORE_IMMEDIATE_BEANINFO) {
newFlags = USE_ALL_BEANINFO;
}
superBeanInfo = getBeanInfo(superClass, stopClass, newFlags);
}
if (explicitBeanInfo != null) {
additionalBeanInfo = explicitBeanInfo.getAdditionalBeanInfo();
}
if (additionalBeanInfo == null) {
additionalBeanInfo = new BeanInfo[0];
}
|
Methods Summary |
---|
private void | addEvent(java.beans.EventSetDescriptor esd)
String key = esd.getName();
if (esd.getName().equals("propertyChange")) {
propertyChangeSource = true;
}
EventSetDescriptor old = (EventSetDescriptor)events.get(key);
if (old == null) {
events.put(key, esd);
return;
}
EventSetDescriptor composite = new EventSetDescriptor(old, esd);
events.put(key, composite);
| private void | addMethod(java.beans.MethodDescriptor md)
// We have to be careful here to distinguish method by both name
// and argument lists.
// This method gets called a *lot, so we try to be efficient.
String name = md.getName();
MethodDescriptor old = (MethodDescriptor)methods.get(name);
if (old == null) {
// This is the common case.
methods.put(name, md);
return;
}
// We have a collision on method names. This is rare.
// Check if old and md have the same type.
String[] p1 = md.getParamNames();
String[] p2 = old.getParamNames();
boolean match = false;
if (p1.length == p2.length) {
match = true;
for (int i = 0; i < p1.length; i++) {
if (p1[i] != p2[i]) {
match = false;
break;
}
}
}
if (match) {
MethodDescriptor composite = new MethodDescriptor(old, md);
methods.put(name, composite);
return;
}
// We have a collision on method names with different type signatures.
// This is very rare.
String longKey = makeQualifiedMethodName(name, p1);
old = (MethodDescriptor)methods.get(longKey);
if (old == null) {
methods.put(longKey, md);
return;
}
MethodDescriptor composite = new MethodDescriptor(old, md);
methods.put(longKey, composite);
| private void | addPropertyDescriptor(java.beans.PropertyDescriptor pd)Adds the property descriptor to the list store.
String propName = pd.getName();
List list = (List)pdStore.get(propName);
if (list == null) {
list = new ArrayList();
pdStore.put(propName, list);
}
list.add(pd);
| public static java.lang.String | decapitalize(java.lang.String name)Utility method to take a string and convert it to normal Java variable
name capitalization. This normally means converting the first
character from upper case to lower case, but in the (unusual) special
case when there is more than one character and both the first and
second characters are upper case, we leave it alone.
Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
as "URL".
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
| private static synchronized java.beans.BeanInfo | findExplicitBeanInfo(java.lang.Class beanClass)Looks for an explicit BeanInfo class that corresponds to the Class.
First it looks in the existing package that the Class is defined in,
then it checks to see if the class is its own BeanInfo. Finally,
the BeanInfo search path is prepended to the class and searched.
String name = beanClass.getName() + BEANINFO_SUFFIX;
try {
return (java.beans.BeanInfo)instantiate(beanClass, name);
} catch (Exception ex) {
// Just drop through
}
// Now try checking if the bean is its own BeanInfo.
try {
if (isSubclass(beanClass, java.beans.BeanInfo.class)) {
return (java.beans.BeanInfo)beanClass.newInstance();
}
} catch (Exception ex) {
// Just drop through
}
// Now try looking for <searchPath>.fooBeanInfo
name = name.substring(name.lastIndexOf('.")+1);
for (int i = 0; i < searchPath.length; i++) {
// This optimization will only use the BeanInfo search path if is has changed
// from the original or trying to get the ComponentBeanInfo.
if (!DEFAULT_INFO_PATH.equals(searchPath[i]) ||
DEFAULT_INFO_PATH.equals(searchPath[i]) && "ComponentBeanInfo".equals(name)) {
try {
String fullName = searchPath[i] + "." + name;
java.beans.BeanInfo bi = (java.beans.BeanInfo)instantiate(beanClass, fullName);
// Make sure that the returned BeanInfo matches the class.
if (bi.getBeanDescriptor() != null) {
if (bi.getBeanDescriptor().getBeanClass() == beanClass) {
return bi;
}
} else if (bi.getPropertyDescriptors() != null) {
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for (int j = 0; j < pds.length; j++) {
Method method = pds[j].getReadMethod();
if (method == null) {
method = pds[j].getWriteMethod();
}
if (method != null && method.getDeclaringClass() == beanClass) {
return bi;
}
}
} else if (bi.getMethodDescriptors() != null) {
MethodDescriptor[] mds = bi.getMethodDescriptors();
for (int j = 0; j < mds.length; j++) {
Method method = mds[j].getMethod();
if (method != null && method.getDeclaringClass() == beanClass) {
return bi;
}
}
}
} catch (Exception ex) {
// Silently ignore any errors.
}
}
}
return null;
| static java.lang.reflect.Method | findMethod(java.lang.Class cls, java.lang.String methodName, int argCount)Find a target methodName on a given class.
return findMethod(cls, methodName, argCount, null);
| static java.lang.reflect.Method | findMethod(java.lang.Class cls, java.lang.String methodName, int argCount, java.lang.Class[] args)Find a target methodName with specific parameter list on a given class.
Used in the contructors of the EventSetDescriptor,
PropertyDescriptor and the IndexedPropertyDescriptor.
if (methodName == null) {
return null;
}
return internalFindMethod(cls, methodName, argCount, args);
| public static void | flushCaches()Flush all of the Introspector's internal caches. This method is
not normally required. It is normally only needed by advanced
tools that update existing "Class" objects in-place and need
to make the Introspector re-analyze existing Class objects.
beanInfoCache.clear();
declaredMethodCache.clear();
| public static void | flushFromCaches(java.lang.Class clz)Flush the Introspector's internal cached information for a given class.
This method is not normally required. It is normally only needed
by advanced tools that update existing "Class" objects in-place
and need to make the Introspector re-analyze an existing Class object.
Note that only the direct state associated with the target Class
object is flushed. We do not flush state for other Class objects
with the same name, nor do we flush state for any related Class
objects (such as subclasses), even though their state may include
information indirectly obtained from the target Class object.
if (clz == null) {
throw new NullPointerException();
}
beanInfoCache.remove(clz);
declaredMethodCache.remove(clz);
| public static java.beans.BeanInfo | getBeanInfo(java.lang.Class beanClass)Introspect on a Java Bean and learn about all its properties, exposed
methods, and events.
If the BeanInfo class for a Java Bean has been previously Introspected
then the BeanInfo class is retrieved from the BeanInfo cache.
//======================================================================
// Public methods
//======================================================================
if (!ReflectUtil.isPackageAccessible(beanClass)) {
return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
}
BeanInfo bi = (BeanInfo)beanInfoCache.get(beanClass);
if (bi == null) {
bi = (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
beanInfoCache.put(beanClass, bi);
}
return bi;
| private java.beans.BeanInfo | getBeanInfo()Constructs a GenericBeanInfo class from the state of the Introspector
// the evaluation order here is import, as we evaluate the
// event sets and locate PropertyChangeListeners before we
// look for properties.
BeanDescriptor bd = getTargetBeanDescriptor();
MethodDescriptor mds[] = getTargetMethodInfo();
EventSetDescriptor esds[] = getTargetEventInfo();
PropertyDescriptor pds[] = getTargetPropertyInfo();
int defaultEvent = getTargetDefaultEventIndex();
int defaultProperty = getTargetDefaultPropertyIndex();
return new GenericBeanInfo(bd, esds, defaultEvent, pds,
defaultProperty, mds, explicitBeanInfo);
| public static java.beans.BeanInfo | getBeanInfo(java.lang.Class beanClass, int flags)Introspect on a Java bean and learn about all its properties, exposed
methods, and events, subject to some control flags.
If the BeanInfo class for a Java Bean has been previously Introspected
based on the same arguments then the BeanInfo class is retrieved
from the BeanInfo cache.
return getBeanInfo(beanClass, null, flags);
| public static java.beans.BeanInfo | getBeanInfo(java.lang.Class beanClass, java.lang.Class stopClass)Introspect on a Java bean and learn all about its properties, exposed
methods, below a given "stop" point.
If the BeanInfo class for a Java Bean has been previously Introspected
based on the same arguments, then the BeanInfo class is retrieved
from the BeanInfo cache.
return getBeanInfo(beanClass, stopClass, USE_ALL_BEANINFO);
| private static java.beans.BeanInfo | getBeanInfo(java.lang.Class beanClass, java.lang.Class stopClass, int flags)Only called from the public getBeanInfo methods. This method caches
the Introspected BeanInfo based on the arguments.
BeanInfo bi;
if (stopClass == null && flags == USE_ALL_BEANINFO) {
// Same parameters to take advantage of caching.
bi = getBeanInfo(beanClass);
} else {
bi = (new Introspector(beanClass, stopClass, flags)).getBeanInfo();
}
return bi;
// Old behaviour: Make an independent copy of the BeanInfo.
//return new GenericBeanInfo(bi);
| public static synchronized java.lang.String[] | getBeanInfoSearchPath()Gets the list of package names that will be used for
finding BeanInfo classes.
// Return a copy of the searchPath.
String result[] = new String[searchPath.length];
for (int i = 0; i < searchPath.length; i++) {
result[i] = searchPath[i];
}
return result;
| private static synchronized java.lang.reflect.Method[] | getPublicDeclaredMethods(java.lang.Class clz)
// Looking up Class.getDeclaredMethods is relatively expensive,
// so we cache the results.
Method[] result = null;
if (!ReflectUtil.isPackageAccessible(clz)) {
return new Method[0];
}
final Class fclz = clz;
Reference ref = (Reference)declaredMethodCache.get(fclz);
if (ref != null) {
result = (Method[])ref.get();
if (result != null) {
return result;
}
}
// We have to raise privilege for getDeclaredMethods
result = (Method[]) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return fclz.getDeclaredMethods();
}
});
// Null out any non-public methods.
for (int i = 0; i < result.length; i++) {
Method method = result[i];
int mods = method.getModifiers();
if (!Modifier.isPublic(mods)) {
result[i] = null;
}
}
// Add it to the cache.
declaredMethodCache.put(fclz, new SoftReference(result));
return result;
| private java.beans.BeanDescriptor | getTargetBeanDescriptor()
// Use explicit info, if available,
if (explicitBeanInfo != null) {
BeanDescriptor bd = explicitBeanInfo.getBeanDescriptor();
if (bd != null) {
return (bd);
}
}
// OK, fabricate a default BeanDescriptor.
return (new BeanDescriptor(beanClass));
| private int | getTargetDefaultEventIndex()
return defaultEventIndex;
| private int | getTargetDefaultPropertyIndex()
return defaultPropertyIndex;
| private java.beans.EventSetDescriptor[] | getTargetEventInfo()
if (events == null) {
events = new HashMap();
}
// Check if the bean has its own BeanInfo that will provide
// explicit information.
EventSetDescriptor[] explicitEvents = null;
if (explicitBeanInfo != null) {
explicitEvents = explicitBeanInfo.getEventSetDescriptors();
int ix = explicitBeanInfo.getDefaultEventIndex();
if (ix >= 0 && ix < explicitEvents.length) {
defaultEventName = explicitEvents[ix].getName();
}
}
if (explicitEvents == null && superBeanInfo != null) {
// We have no explicit BeanInfo events. Check with our parent.
EventSetDescriptor supers[] = superBeanInfo.getEventSetDescriptors();
for (int i = 0 ; i < supers.length; i++) {
addEvent(supers[i]);
}
int ix = superBeanInfo.getDefaultEventIndex();
if (ix >= 0 && ix < supers.length) {
defaultEventName = supers[ix].getName();
}
}
for (int i = 0; i < additionalBeanInfo.length; i++) {
EventSetDescriptor additional[] = additionalBeanInfo[i].getEventSetDescriptors();
if (additional != null) {
for (int j = 0 ; j < additional.length; j++) {
addEvent(additional[j]);
}
}
}
if (explicitEvents != null) {
// Add the explicit explicitBeanInfo data to our results.
for (int i = 0 ; i < explicitEvents.length; i++) {
addEvent(explicitEvents[i]);
}
} else {
// Apply some reflection to the current class.
// Get an array of all the public beans methods at this level
Method methodList[] = getPublicDeclaredMethods(beanClass);
// Find all suitable "add", "remove" and "get" Listener methods
// The name of the listener type is the key for these hashtables
// i.e, ActionListener
Map adds = null;
Map removes = null;
Map gets = null;
for (int i = 0; i < methodList.length; i++) {
Method method = methodList[i];
if (method == null) {
continue;
}
// skip static methods.
int mods = method.getModifiers();
if (Modifier.isStatic(mods)) {
continue;
}
String name = method.getName();
// Optimization avoid getParameterTypes
if (!name.startsWith(ADD_PREFIX) && !name.startsWith(REMOVE_PREFIX)
&& !name.startsWith(GET_PREFIX)) {
continue;
}
Class argTypes[] = method.getParameterTypes();
Class resultType = method.getReturnType();
if (name.startsWith(ADD_PREFIX) && argTypes.length == 1 &&
resultType == Void.TYPE &&
Introspector.isSubclass(argTypes[0], eventListenerType)) {
String listenerName = name.substring(3);
if (listenerName.length() > 0 &&
argTypes[0].getName().endsWith(listenerName)) {
if (adds == null) {
adds = new HashMap();
}
adds.put(listenerName, method);
}
}
else if (name.startsWith(REMOVE_PREFIX) && argTypes.length == 1 &&
resultType == Void.TYPE &&
Introspector.isSubclass(argTypes[0], eventListenerType)) {
String listenerName = name.substring(6);
if (listenerName.length() > 0 &&
argTypes[0].getName().endsWith(listenerName)) {
if (removes == null) {
removes = new HashMap();
}
removes.put(listenerName, method);
}
}
else if (name.startsWith(GET_PREFIX) && argTypes.length == 0 &&
resultType.isArray() &&
Introspector.isSubclass(resultType.getComponentType(),
eventListenerType)) {
String listenerName = name.substring(3, name.length() - 1);
if (listenerName.length() > 0 &&
resultType.getComponentType().getName().endsWith(listenerName)) {
if (gets == null) {
gets = new HashMap();
}
gets.put(listenerName, method);
}
}
}
if (adds != null && removes != null) {
// Now look for matching addFooListener+removeFooListener pairs.
// Bonus if there is a matching getFooListeners method as well.
Iterator keys = adds.keySet().iterator();
while (keys.hasNext()) {
String listenerName = (String) keys.next();
// Skip any "add" which doesn't have a matching "remove" or
// a listener name that doesn't end with Listener
if (removes.get(listenerName) == null || !listenerName.endsWith("Listener")) {
continue;
}
String eventName = decapitalize(listenerName.substring(0, listenerName.length()-8));
Method addMethod = (Method)adds.get(listenerName);
Method removeMethod = (Method)removes.get(listenerName);
Method getMethod = null;
if (gets != null) {
getMethod = (Method)gets.get(listenerName);
}
Class argType = addMethod.getParameterTypes()[0];
// generate a list of Method objects for each of the target methods:
Method allMethods[] = getPublicDeclaredMethods(argType);
List validMethods = new ArrayList(allMethods.length);
for (int i = 0; i < allMethods.length; i++) {
if (allMethods[i] == null) {
continue;
}
if (isEventHandler(allMethods[i])) {
validMethods.add(allMethods[i]);
}
}
Method[] methods = (Method[])validMethods.toArray(new Method[validMethods.size()]);
EventSetDescriptor esd = new EventSetDescriptor(eventName, argType,
methods, addMethod,
removeMethod,
getMethod);
// If the adder method throws the TooManyListenersException then it
// is a Unicast event source.
if (throwsException(addMethod,
java.util.TooManyListenersException.class)) {
esd.setUnicast(true);
}
addEvent(esd);
}
} // if (adds != null ...
}
EventSetDescriptor[] result;
if (events.size() == 0) {
result = EMPTY_EVENTSETDESCRIPTORS;
} else {
// Allocate and populate the result array.
result = new EventSetDescriptor[events.size()];
result = (EventSetDescriptor[])events.values().toArray(result);
// Set the default index.
if (defaultEventName != null) {
for (int i = 0; i < result.length; i++) {
if (defaultEventName.equals(result[i].getName())) {
defaultEventIndex = i;
}
}
}
}
return result;
| private java.beans.MethodDescriptor[] | getTargetMethodInfo()
if (methods == null) {
methods = new HashMap(100);
}
// Check if the bean has its own BeanInfo that will provide
// explicit information.
MethodDescriptor[] explicitMethods = null;
if (explicitBeanInfo != null) {
explicitMethods = explicitBeanInfo.getMethodDescriptors();
}
if (explicitMethods == null && superBeanInfo != null) {
// We have no explicit BeanInfo methods. Check with our parent.
MethodDescriptor supers[] = superBeanInfo.getMethodDescriptors();
for (int i = 0 ; i < supers.length; i++) {
addMethod(supers[i]);
}
}
for (int i = 0; i < additionalBeanInfo.length; i++) {
MethodDescriptor additional[] = additionalBeanInfo[i].getMethodDescriptors();
if (additional != null) {
for (int j = 0 ; j < additional.length; j++) {
addMethod(additional[j]);
}
}
}
if (explicitMethods != null) {
// Add the explicit explicitBeanInfo data to our results.
for (int i = 0 ; i < explicitMethods.length; i++) {
addMethod(explicitMethods[i]);
}
} else {
// Apply some reflection to the current class.
// First get an array of all the beans methods at this level
Method methodList[] = getPublicDeclaredMethods(beanClass);
// Now analyze each method.
for (int i = 0; i < methodList.length; i++) {
Method method = methodList[i];
if (method == null) {
continue;
}
MethodDescriptor md = new MethodDescriptor(method);
addMethod(md);
}
}
// Allocate and populate the result array.
MethodDescriptor result[] = new MethodDescriptor[methods.size()];
result = (MethodDescriptor[])methods.values().toArray(result);
return result;
| private java.beans.PropertyDescriptor[] | getTargetPropertyInfo()
// Check if the bean has its own BeanInfo that will provide
// explicit information.
PropertyDescriptor[] explicitProperties = null;
if (explicitBeanInfo != null) {
explicitProperties = explicitBeanInfo.getPropertyDescriptors();
int ix = explicitBeanInfo.getDefaultPropertyIndex();
if (ix >= 0 && ix < explicitProperties.length) {
defaultPropertyName = explicitProperties[ix].getName();
}
}
if (explicitProperties == null && superBeanInfo != null) {
// We have no explicit BeanInfo properties. Check with our parent.
PropertyDescriptor supers[] = superBeanInfo.getPropertyDescriptors();
for (int i = 0 ; i < supers.length; i++) {
addPropertyDescriptor(supers[i]);
}
int ix = superBeanInfo.getDefaultPropertyIndex();
if (ix >= 0 && ix < supers.length) {
defaultPropertyName = supers[ix].getName();
}
}
for (int i = 0; i < additionalBeanInfo.length; i++) {
PropertyDescriptor additional[] = additionalBeanInfo[i].getPropertyDescriptors();
if (additional != null) {
for (int j = 0 ; j < additional.length; j++) {
addPropertyDescriptor(additional[j]);
}
}
}
if (explicitProperties != null) {
// Add the explicit BeanInfo data to our results.
for (int i = 0 ; i < explicitProperties.length; i++) {
addPropertyDescriptor(explicitProperties[i]);
}
} else {
// Apply some reflection to the current class.
// First get an array of all the public methods at this level
Method methodList[] = getPublicDeclaredMethods(beanClass);
// Now analyze each method.
for (int i = 0; i < methodList.length; i++) {
Method method = methodList[i];
if (method == null) {
continue;
}
// skip static methods.
int mods = method.getModifiers();
if (Modifier.isStatic(mods)) {
continue;
}
String name = method.getName();
Class argTypes[] = method.getParameterTypes();
Class resultType = method.getReturnType();
int argCount = argTypes.length;
PropertyDescriptor pd = null;
if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) {
// Optimization. Don't bother with invalid propertyNames.
continue;
}
try {
if (argCount == 0) {
if (name.startsWith(GET_PREFIX)) {
// Simple getter
pd = new PropertyDescriptor(decapitalize(name.substring(3)),
method, null);
} else if (resultType == boolean.class && name.startsWith(IS_PREFIX)) {
// Boolean getter
pd = new PropertyDescriptor(decapitalize(name.substring(2)),
method, null);
}
} else if (argCount == 1) {
if (argTypes[0] == int.class && name.startsWith(GET_PREFIX)) {
pd = new IndexedPropertyDescriptor(
decapitalize(name.substring(3)),
null, null,
method, null);
} else if (resultType == void.class && name.startsWith(SET_PREFIX)) {
// Simple setter
pd = new PropertyDescriptor(decapitalize(name.substring(3)),
null, method);
if (throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
} else if (argCount == 2) {
if (argTypes[0] == int.class && name.startsWith(SET_PREFIX)) {
pd = new IndexedPropertyDescriptor(
decapitalize(name.substring(3)),
null, null,
null, method);
if (throwsException(method, PropertyVetoException.class)) {
pd.setConstrained(true);
}
}
}
} catch (IntrospectionException ex) {
// This happens if a PropertyDescriptor or IndexedPropertyDescriptor
// constructor fins that the method violates details of the deisgn
// pattern, e.g. by having an empty name, or a getter returning
// void , or whatever.
pd = null;
}
if (pd != null) {
// If this class or one of its base classes is a PropertyChange
// source, then we assume that any properties we discover are "bound".
if (propertyChangeSource) {
pd.setBound(true);
}
addPropertyDescriptor(pd);
}
}
}
processPropertyDescriptors();
// Allocate and populate the result array.
PropertyDescriptor result[] = new PropertyDescriptor[properties.size()];
result = (PropertyDescriptor[])properties.values().toArray(result);
// Set the default index.
if (defaultPropertyName != null) {
for (int i = 0; i < result.length; i++) {
if (defaultPropertyName.equals(result[i].getName())) {
defaultPropertyIndex = i;
}
}
}
return result;
| static java.lang.Object | instantiate(java.lang.Class sibling, java.lang.String className)Try to create an instance of a named class.
First try the classloader of "sibling", then try the system
classloader then the class loader of the current Thread.
// First check with sibling's classloader (if any).
ClassLoader cl = sibling.getClassLoader();
if (cl != null) {
try {
Class cls = cl.loadClass(className);
return cls.newInstance();
} catch (Exception ex) {
// Just drop through and try the system classloader.
}
}
// Now try the system classloader.
try {
cl = ClassLoader.getSystemClassLoader();
if (cl != null) {
Class cls = cl.loadClass(className);
return cls.newInstance();
}
} catch (Exception ex) {
// We're not allowed to access the system class loader or
// the class creation failed.
// Drop through.
}
// Use the classloader from the current Thread.
cl = Thread.currentThread().getContextClassLoader();
Class cls = cl.loadClass(className);
return cls.newInstance();
| private static java.lang.reflect.Method | internalFindMethod(java.lang.Class start, java.lang.String methodName, int argCount, java.lang.Class[] args)Internal support for finding a target methodName with a given
parameter list on a given class.
// For overriden methods we need to find the most derived version.
// So we start with the given class and walk up the superclass chain.
Method method = null;
for (Class cl = start; cl != null; cl = cl.getSuperclass()) {
Method methods[] = getPublicDeclaredMethods(cl);
for (int i = 0; i < methods.length; i++) {
method = methods[i];
if (method == null) {
continue;
}
// make sure method signature matches.
Class params[] = method.getParameterTypes();
if (method.getName().equals(methodName) &&
params.length == argCount) {
if (args != null) {
boolean different = false;
if (argCount > 0) {
for (int j = 0; j < argCount; j++) {
if (params[j] != args[j]) {
different = true;
continue;
}
}
if (different) {
continue;
}
}
}
return method;
}
}
}
method = null;
// Now check any inherited interfaces. This is necessary both when
// the argument class is itself an interface, and when the argument
// class is an abstract class.
Class ifcs[] = start.getInterfaces();
for (int i = 0 ; i < ifcs.length; i++) {
// Note: The original implementation had both methods calling
// the 3 arg method. This is preserved but perhaps it should
// pass the args array instead of null.
method = internalFindMethod(ifcs[i], methodName, argCount, null);
if (method != null) {
break;
}
}
return method;
| private boolean | isEventHandler(java.lang.reflect.Method m)
// We assume that a method is an event handler if it has a single
// argument, whose type inherit from java.util.Event.
Class argTypes[] = m.getParameterTypes();
if (argTypes.length != 1) {
return false;
}
if (isSubclass(argTypes[0], java.util.EventObject.class)) {
return true;
}
return false;
| static boolean | isSubclass(java.lang.Class a, java.lang.Class b)Return true if class a is either equivalent to class b, or
if class a is a subclass of class b, i.e. if a either "extends"
or "implements" b.
Note tht either or both "Class" objects may represent interfaces.
// We rely on the fact that for any given java class or
// primtitive type there is a unqiue Class object, so
// we can use object equivalence in the comparisons.
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
for (Class x = a; x != null; x = x.getSuperclass()) {
if (x == b) {
return true;
}
if (b.isInterface()) {
Class interfaces[] = x.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
if (isSubclass(interfaces[i], b)) {
return true;
}
}
}
}
return false;
| private static java.lang.String | makeQualifiedMethodName(java.lang.String name, java.lang.String[] params)Creates a key for a method in a method cache.
StringBuffer sb = new StringBuffer(name);
sb.append('=");
for (int i = 0; i < params.length; i++) {
sb.append(':");
sb.append(params[i]);
}
return sb.toString();
| private java.beans.PropertyDescriptor | mergePropertyDescriptor(java.beans.IndexedPropertyDescriptor ipd, java.beans.PropertyDescriptor pd)Adds the property descriptor to the indexedproperty descriptor only if the
types are the same.
The most specific property descriptor will take precedence.
PropertyDescriptor result = null;
Class propType = pd.getPropertyType();
Class ipropType = ipd.getIndexedPropertyType();
if (propType.isArray() && propType.getComponentType() == ipropType) {
if (pd.getClass0().isAssignableFrom(ipd.getClass0())) {
result = new IndexedPropertyDescriptor(pd, ipd);
} else {
result = new IndexedPropertyDescriptor(ipd, pd);
}
} else {
// Cannot merge the pd because of type mismatch
// Return the most specific pd
if (pd.getClass0().isAssignableFrom(ipd.getClass0())) {
result = ipd;
} else {
result = pd;
// Try to add methods which may have been lost in the type change
// See 4168833
Method write = result.getWriteMethod();
Method read = result.getReadMethod();
if (read == null && write != null) {
read = findMethod(result.getClass0(),
"get" + result.capitalize(result.getName()), 0);
if (read != null) {
try {
result.setReadMethod(read);
} catch (IntrospectionException ex) {
// no consequences for failure.
}
}
}
if (write == null && read != null) {
write = findMethod(result.getClass0(),
"set" + result.capitalize(result.getName()), 1,
new Class[] { read.getReturnType() });
if (write != null) {
try {
result.setWriteMethod(write);
} catch (IntrospectionException ex) {
// no consequences for failure.
}
}
}
}
}
return result;
| private java.beans.PropertyDescriptor | mergePropertyDescriptor(java.beans.PropertyDescriptor pd1, java.beans.PropertyDescriptor pd2)
if (pd1.getClass0().isAssignableFrom(pd2.getClass0())) {
return new PropertyDescriptor(pd1, pd2);
} else {
return new PropertyDescriptor(pd2, pd1);
}
| private java.beans.PropertyDescriptor | mergePropertyDescriptor(java.beans.IndexedPropertyDescriptor ipd1, java.beans.IndexedPropertyDescriptor ipd2)
if (ipd1.getClass0().isAssignableFrom(ipd2.getClass0())) {
return new IndexedPropertyDescriptor(ipd1, ipd2);
} else {
return new IndexedPropertyDescriptor(ipd2, ipd1);
}
| private void | processPropertyDescriptors()Populates the property descriptor table by merging the
lists of Property descriptors.
if (properties == null) {
properties = new TreeMap();
}
List list;
PropertyDescriptor pd, gpd, spd;
IndexedPropertyDescriptor ipd, igpd, ispd;
Iterator it = pdStore.values().iterator();
while (it.hasNext()) {
pd = null; gpd = null; spd = null;
ipd = null; igpd = null; ispd = null;
list = (List)it.next();
// First pass. Find the latest getter method. Merge properties
// of previous getter methods.
for (int i = 0; i < list.size(); i++) {
pd = (PropertyDescriptor)list.get(i);
if (pd instanceof IndexedPropertyDescriptor) {
ipd = (IndexedPropertyDescriptor)pd;
if (ipd.getIndexedReadMethod() != null) {
if (igpd != null) {
igpd = new IndexedPropertyDescriptor(igpd, ipd);
} else {
igpd = ipd;
}
}
} else {
if (pd.getReadMethod() != null) {
if (gpd != null) {
// Don't replace the existing read
// method if it starts with "is"
Method method = gpd.getReadMethod();
if (!method.getName().startsWith(IS_PREFIX)) {
gpd = new PropertyDescriptor(gpd, pd);
}
} else {
gpd = pd;
}
}
}
}
// Second pass. Find the latest setter method which
// has the same type as the getter method.
for (int i = 0; i < list.size(); i++) {
pd = (PropertyDescriptor)list.get(i);
if (pd instanceof IndexedPropertyDescriptor) {
ipd = (IndexedPropertyDescriptor)pd;
if (ipd.getIndexedWriteMethod() != null) {
if (igpd != null) {
if (igpd.getIndexedPropertyType()
== ipd.getIndexedPropertyType()) {
if (ispd != null) {
ispd = new IndexedPropertyDescriptor(ispd, ipd);
} else {
ispd = ipd;
}
}
} else {
if (ispd != null) {
ispd = new IndexedPropertyDescriptor(ispd, ipd);
} else {
ispd = ipd;
}
}
}
} else {
if (pd.getWriteMethod() != null) {
if (gpd != null) {
if (gpd.getPropertyType() == pd.getPropertyType()) {
if (spd != null) {
spd = new PropertyDescriptor(spd, pd);
} else {
spd = pd;
}
}
} else {
if (spd != null) {
spd = new PropertyDescriptor(spd, pd);
} else {
spd = pd;
}
}
}
}
}
// At this stage we should have either PDs or IPDs for the
// representative getters and setters. The order at which the
// property descriptors are determined represent the
// precedence of the property ordering.
pd = null; ipd = null;
if (igpd != null && ispd != null) {
// Complete indexed properties set
// Merge any classic property descriptors
if (gpd != null) {
PropertyDescriptor tpd = mergePropertyDescriptor(igpd, gpd);
if (tpd instanceof IndexedPropertyDescriptor) {
igpd = (IndexedPropertyDescriptor)tpd;
}
}
if (spd != null) {
PropertyDescriptor tpd = mergePropertyDescriptor(ispd, spd);
if (tpd instanceof IndexedPropertyDescriptor) {
ispd = (IndexedPropertyDescriptor)tpd;
}
}
if (igpd == ispd) {
pd = igpd;
} else {
pd = mergePropertyDescriptor(igpd, ispd);
}
} else if (gpd != null && spd != null) {
// Complete simple properties set
if (gpd == spd) {
pd = gpd;
} else {
pd = mergePropertyDescriptor(gpd, spd);
}
} else if (ispd != null) {
// indexed setter
pd = ispd;
// Merge any classic property descriptors
if (spd != null) {
pd = mergePropertyDescriptor(ispd, spd);
}
if (gpd != null) {
pd = mergePropertyDescriptor(ispd, gpd);
}
} else if (igpd != null) {
// indexed getter
pd = igpd;
// Merge any classic property descriptors
if (gpd != null) {
pd = mergePropertyDescriptor(igpd, gpd);
}
if (spd != null) {
pd = mergePropertyDescriptor(igpd, spd);
}
} else if (spd != null) {
// simple setter
pd = spd;
} else if (gpd != null) {
// simple getter
pd = gpd;
}
// Very special case to ensure that an IndexedPropertyDescriptor
// doesn't contain less information than the enclosed
// PropertyDescriptor. If it does, then recreate as a
// PropertyDescriptor. See 4168833
if (pd instanceof IndexedPropertyDescriptor) {
ipd = (IndexedPropertyDescriptor)pd;
if (ipd.getIndexedReadMethod() == null && ipd.getIndexedWriteMethod() == null) {
pd = new PropertyDescriptor(ipd);
}
}
// Find the first property descriptor
// which does not have getter and setter methods.
// See regression bug 4984912.
if ( (pd == null) && (list.size() > 0) ) {
pd = (PropertyDescriptor) list.get(0);
}
if (pd != null) {
properties.put(pd.getName(), pd);
}
}
| public static synchronized void | setBeanInfoSearchPath(java.lang.String[] path)Change the list of package names that will be used for
finding BeanInfo classes. The behaviour of
this method is undefined if parameter path
is null.
First, if there is a security manager, its checkPropertiesAccess
method is called. This could result in a SecurityException.
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertiesAccess();
}
searchPath = path;
| private boolean | throwsException(java.lang.reflect.Method method, java.lang.Class exception)Return true iff the given method throws the given exception.
Class exs[] = method.getExceptionTypes();
for (int i = 0; i < exs.length; i++) {
if (exs[i] == exception) {
return true;
}
}
return false;
|
|