57 |
|
|
58 |
/** |
/** |
59 |
** IntrospectionIncubator takes in a bunch of Methods, and |
** IntrospectionIncubator takes in a bunch of Methods, and |
60 |
** Introspects only those Methods you give it. |
** Introspects only those Methods you give it.<br/> |
61 |
** Note that non-public and static methods are silently |
** |
62 |
** discarded. |
** See {@link addMethod(Method)} for details which rules apply to |
63 |
|
** the methods. |
64 |
** |
** |
65 |
** @author John Keiser |
** @author John Keiser |
66 |
** @author Robert Schuster |
** @author Robert Schuster |
80 |
public IntrospectionIncubator() { |
public IntrospectionIncubator() { |
81 |
} |
} |
82 |
|
|
83 |
/* Paving the way for automatic Introspection */ |
/** Examines the given method and files it in a suitable collection. |
84 |
|
* It files the method as a property method if it finds: |
85 |
|
* <lu> |
86 |
|
* <li>boolean "is" getter</li> |
87 |
|
* <li>"get" style getter</li> |
88 |
|
* <li>single argument setter</li> |
89 |
|
* <li>indiced setter and getter</li> |
90 |
|
* </ul> |
91 |
|
* It files the method as a listener method if all of these rules apply: |
92 |
|
* <lu> |
93 |
|
* <li>the method name starts with "add" or "remove"</li> |
94 |
|
* <li>there is only a single argument</li> |
95 |
|
* <li>the argument type is a subclass of <code>java.util.EventListener</code></li> |
96 |
|
* </ul> |
97 |
|
* All public methods are filed as such. |
98 |
|
* |
99 |
|
* @param method The method instance to examine. |
100 |
|
*/ |
101 |
public void addMethod(Method method) { |
public void addMethod(Method method) { |
102 |
if(Modifier.isPublic(method.getModifiers()) && |
if(Modifier.isPublic(method.getModifiers())) { |
|
!Modifier.isStatic(method.getModifiers())) { |
|
103 |
String name = ClassHelper.getTruncatedName(method.getName()); |
String name = ClassHelper.getTruncatedName(method.getName()); |
104 |
Class retType = method.getReturnType(); |
Class retType = method.getReturnType(); |
105 |
Class[] params = method.getParameterTypes(); |
Class[] params = method.getParameterTypes(); |
106 |
boolean isVoid = retType.equals(java.lang.Void.TYPE); |
boolean isVoid = retType.equals(java.lang.Void.TYPE); |
107 |
Class methodClass = method.getDeclaringClass(); |
Class methodClass = method.getDeclaringClass(); |
108 |
if(propertyStopClass == null || (propertyStopClass.isAssignableFrom(methodClass) && !propertyStopClass.equals(methodClass))) { |
|
109 |
if(name.startsWith("is") |
/* Accepts the method for examination if no stop class is given or the method is declared in a subclass of the stop class. |
110 |
|
* The rules for this are described in {@link java.beans.Introspector.getBeanInfo(Class, Class)}. |
111 |
|
* This block finds out whether the method is a suitable getter or setter method (or read/write method). |
112 |
|
*/ |
113 |
|
if(isReachable(propertyStopClass, methodClass)) { |
114 |
|
/* At this point a method may regarded as a property's read or write method if its name |
115 |
|
* starts with "is", "get" or "set". However, if a method is static it cannot be part |
116 |
|
* of a property. |
117 |
|
*/ |
118 |
|
if(Modifier.isStatic(method.getModifiers())) { |
119 |
|
// files method as other because it is static |
120 |
|
otherMethods.addElement(method); |
121 |
|
} else if(name.startsWith("is") |
122 |
&& retType.equals(java.lang.Boolean.TYPE) |
&& retType.equals(java.lang.Boolean.TYPE) |
123 |
&& params.length == 0) { |
&& params.length == 0) { |
124 |
|
// files method as boolean "is" style getter |
125 |
addToPropertyHash(name,method,IS); |
addToPropertyHash(name,method,IS); |
126 |
} else if(name.startsWith("get") && !isVoid) { |
} else if(name.startsWith("get") && !isVoid) { |
127 |
if(params.length == 0) { |
if(params.length == 0) { |
128 |
|
// files as legal non-argument getter |
129 |
addToPropertyHash(name,method,GET); |
addToPropertyHash(name,method,GET); |
130 |
} else if(params.length == 1 && params[0].equals(java.lang.Integer.TYPE)) { |
} else if(params.length == 1 && params[0].equals(java.lang.Integer.TYPE)) { |
131 |
|
// files as legal indiced getter |
132 |
addToPropertyHash(name,method,GET_I); |
addToPropertyHash(name,method,GET_I); |
133 |
} else { |
} else { |
134 |
|
// files as other because the method's signature is not Bean-like |
135 |
otherMethods.addElement(method); |
otherMethods.addElement(method); |
136 |
} |
} |
137 |
} else if(name.startsWith("set") && isVoid) { |
} else if(name.startsWith("set") && isVoid) { |
138 |
if(params.length == 1) { |
if(params.length == 1) { |
139 |
|
// files as legal single-argument setter method |
140 |
addToPropertyHash(name,method,SET); |
addToPropertyHash(name,method,SET); |
141 |
} else if(params.length == 2 && params[0].equals(java.lang.Integer.TYPE)) { |
} else if(params.length == 2 && params[0].equals(java.lang.Integer.TYPE)) { |
142 |
|
// files as legal indiced setter method |
143 |
addToPropertyHash(name,method,SET_I); |
addToPropertyHash(name,method,SET_I); |
144 |
} else { |
} else { |
145 |
|
// files as other because the method's signature is not Bean-like |
146 |
otherMethods.addElement(method); |
otherMethods.addElement(method); |
147 |
} |
} |
148 |
} |
} |
149 |
} |
} |
150 |
if(eventStopClass == null || (eventStopClass.isAssignableFrom(methodClass) && !eventStopClass.equals(methodClass))) { |
|
151 |
|
if(isReachable(eventStopClass, methodClass)) { |
152 |
if(name.startsWith("add") |
if(name.startsWith("add") |
153 |
&& isVoid |
&& isVoid |
154 |
&& params.length == 1 |
&& params.length == 1 |
161 |
addToListenerHash(name,method,REMOVE); |
addToListenerHash(name,method,REMOVE); |
162 |
} |
} |
163 |
} |
} |
164 |
if(methodStopClass == null || (methodStopClass.isAssignableFrom(methodClass) && !methodStopClass.equals(methodClass))) { |
|
165 |
|
if(isReachable(methodStopClass, methodClass)) { |
166 |
|
// files as reachable public method |
167 |
otherMethods.addElement(method); |
otherMethods.addElement(method); |
168 |
} |
} |
169 |
|
|
170 |
} |
} |
171 |
} |
} |
172 |
|
|
333 |
methods[funcType] = method; |
methods[funcType] = method; |
334 |
} |
} |
335 |
|
|
|
|
|
336 |
void addToListenerHash(String name, Method method, int funcType) { |
void addToListenerHash(String name, Method method, int funcType) { |
337 |
String newName; |
String newName; |
338 |
Class type; |
Class type; |
360 |
methods[funcType] = method; |
methods[funcType] = method; |
361 |
} |
} |
362 |
|
|
363 |
|
/* Determines whether <code>stopClass</code> is <code>null</code> |
364 |
|
* or <code>declaringClass<code> is a true subclass of <code>stopClass</code>. |
365 |
|
* This expression is useful to detect whether a method should be introspected or not. |
366 |
|
* The rules for this are described in {@link java.beans.Introspector.getBeanInfo(Class, Class)}. |
367 |
|
*/ |
368 |
|
static boolean isReachable(Class stopClass, Class declaringClass) { |
369 |
|
return stopClass == null || (stopClass.isAssignableFrom(declaringClass) && !stopClass.equals(declaringClass)); |
370 |
|
} |
371 |
|
|
372 |
|
/** Transforms a property name into a part of a method name. |
373 |
|
* E.g. "value" becomes "Value" which can then concatenated with |
374 |
|
* "set", "get" or "is" to form a valid method name. |
375 |
|
* |
376 |
|
* Implementation notes: |
377 |
|
* If "" is the argument, it is returned without changes. |
378 |
|
* If <code>null</code> is the argument, <code>null</code> is returned. |
379 |
|
* |
380 |
|
* @param name Name of a property. |
381 |
|
* @return Part of a method name of a property. |
382 |
|
*/ |
383 |
static String capitalize(String name) { |
static String capitalize(String name) { |
384 |
try { |
try { |
385 |
if(Character.isUpperCase(name.charAt(0))) { |
if(Character.isUpperCase(name.charAt(0))) { |
397 |
} |
} |
398 |
} |
} |
399 |
|
|
400 |
|
/** This class is a hashmap key that consists of a <code>Class</code> and a |
401 |
|
* <code>String</code> element. |
402 |
|
* |
403 |
|
* It is used for XXX: find out what this is used for |
404 |
|
* |
405 |
|
* @author John Keiser |
406 |
|
* @author Robert Schuster |
407 |
|
*/ |
408 |
class DoubleKey { |
class DoubleKey { |
409 |
Class type; |
Class type; |
410 |
String name; |
String name; |