KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jodd > util > ReflectUtil


1 // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
2

3 package jodd.util;
4
5 import java.lang.reflect.InvocationTargetException JavaDoc;
6 import java.lang.reflect.Method JavaDoc;
7 import java.lang.reflect.Modifier JavaDoc;
8 import java.lang.reflect.AccessibleObject JavaDoc;
9 import java.lang.reflect.Member JavaDoc;
10 import java.lang.reflect.Constructor JavaDoc;
11 import java.lang.reflect.Field JavaDoc;
12 import java.lang.reflect.Array JavaDoc;
13 import java.util.*;
14
15 /**
16  * Various java.lang.reflect utilities.
17  */

18 public class ReflectUtil {
19
20
21     // ---------------------------------------------------------------- method0
22

23     private static Method JavaDoc _getMethod0 = null;
24     static {
25         try {
26             _getMethod0 = Class JavaDoc.class.getDeclaredMethod("getMethod0", new Class JavaDoc[] {String JavaDoc.class, Class JavaDoc[].class});
27             _getMethod0.setAccessible(true);
28         } catch (Exception JavaDoc e) {
29             try {
30                 _getMethod0 = Class JavaDoc.class.getMethod("getMethod", new Class JavaDoc[] {String JavaDoc.class, Class JavaDoc[].class});
31             } catch (Exception JavaDoc ex) {
32                 _getMethod0 = null;
33             }
34         }
35     }
36
37     /**
38      * Invokes private <code>Class.getMethod0()</code> without throwing NoSuchMethod exception.
39      * Returns only public methods or <code>null</code> if method not found.
40      *
41      * @param c class to inspect
42      * @param name name of method to find
43      * @param parameterTypes parameter types
44      * @return founded method, or null
45      */

46     public static Method JavaDoc getMethod0(Class JavaDoc c, String JavaDoc name, Class JavaDoc[] parameterTypes) {
47         try {
48             return (Method JavaDoc) _getMethod0.invoke(c, new Object JavaDoc[]{name, parameterTypes});
49         } catch (Exception JavaDoc ex) {
50             return null;
51         }
52     }
53
54     /**
55      * Invokes private <code>Class.getMethod0()</code> without throwing NoSuchMethod exception.
56      * Returns only accessible methods.
57      *
58      * @param o object to inspect
59      * @param name name of method to find
60      * @param parameterTypes parameter types
61      * @return founded method, or null
62      */

63     public static Method JavaDoc getMethod0(Object JavaDoc o, String JavaDoc name, Class JavaDoc[] parameterTypes) {
64         try {
65             return (Method JavaDoc) _getMethod0.invoke(o.getClass(), new Object JavaDoc[]{name, parameterTypes});
66         } catch (Exception JavaDoc ex) {
67             return null;
68         }
69     }
70
71     // ---------------------------------------------------------------- find method
72

73     /**
74      * Returns method from an object, matched by name. This may be considered as
75      * a slow operation, since methods are matched one by one.
76      * Returns only accessible methods.
77      * Only first method is matched.
78      *
79      * @param c class to examine
80      * @param methodName Full name of the method.
81      * @return null if method not found
82      */

83     public static Method JavaDoc findMethod(Class JavaDoc c, String JavaDoc methodName) {
84         return findDeclaredMethod(c, methodName, true);
85     }
86
87     public static Method JavaDoc findDeclaredMethod(Class JavaDoc c, String JavaDoc methodName) {
88         return findDeclaredMethod(c, methodName, false);
89     }
90
91
92     private static Method JavaDoc findDeclaredMethod(Class JavaDoc c, String JavaDoc methodName, boolean publicOnly) {
93         if ((methodName == null) || (c == null)) {
94             return null;
95         }
96         Method JavaDoc[] ms = publicOnly ? c.getMethods() : c.getDeclaredMethods();
97         for (int i = 0; i < ms.length; i++) {
98             Method JavaDoc m = ms[i];
99             if (m.getName().equals(methodName)) {
100                 return m;
101             }
102         }
103         return null;
104
105     }
106
107
108     // ---------------------------------------------------------------- classes
109

110     /**
111      * Returns classes from array of specified objects.
112      */

113     public static Class JavaDoc[] getClasses(Object JavaDoc objects[]) {
114         if (objects == null) {
115             return null;
116         }
117         Class JavaDoc[] classes = new Class JavaDoc[objects.length];
118         for (int i = 0; i < objects.length; i++) {
119             if (objects[i] != null) {
120                 classes[i] = objects[i].getClass();
121             }
122         }
123         return classes;
124     }
125
126
127     // ---------------------------------------------------------------- invoke
128

129
130     /**
131      * Invokes accessible method of an object.
132      *
133      * @param c class that contains method
134      * @param obj object to execute
135      * @param method method to invoke
136      * @param paramClasses classes of parameters
137      * @param params parameters
138 � */

139     public static Object JavaDoc invoke(Class JavaDoc c, Object JavaDoc obj, String JavaDoc method, Class JavaDoc[] paramClasses, Object JavaDoc[] params) throws IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
140         Method JavaDoc m = c.getMethod(method, paramClasses);
141         return m.invoke(obj, params);
142     }
143
144
145     /**
146      * Invokes accessible method of an object.
147      *
148      * @param obj object
149      * @param method name of the objects method
150      * @param params method parameters
151      * @param paramClasses method parameter types
152      */

153     public static Object JavaDoc invoke(Object JavaDoc obj, String JavaDoc method, Class JavaDoc[] paramClasses, Object JavaDoc[] params) throws IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
154         Method JavaDoc m = obj.getClass().getMethod(method, paramClasses);
155         return m.invoke(obj, params);
156     }
157
158     /**
159      * Invokes accessible method of an object without specifying parameter types.
160      * @param obj object
161      * @param method method of an object
162      * @param params method parameters
163      */

164     public static Object JavaDoc invoke(Object JavaDoc obj, String JavaDoc method, Object JavaDoc[] params) throws IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
165         Class JavaDoc[] paramClass = getClasses(params);
166         return invoke(obj, method, paramClass, params);
167     }
168
169     public static Object JavaDoc invoke(Class JavaDoc c, Object JavaDoc obj, String JavaDoc method, Object JavaDoc[] params) throws IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
170         Class JavaDoc[] paramClass = getClasses(params);
171         return invoke(c, obj, method, paramClass, params);
172     }
173
174
175     // ---------------------------------------------------------------- invokeDeclared
176

177
178     /**
179      * Invokes any method of a class, even private ones.
180      *
181      * @param c class to examine
182      * @param obj object to inspect
183      * @param method method to invoke
184      * @param paramClasses parameter types
185      * @param params parameters
186      */

187     public static Object JavaDoc invokeDeclared(Class JavaDoc c, Object JavaDoc obj, String JavaDoc method, Class JavaDoc[] paramClasses, Object JavaDoc[] params) throws IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
188         Method JavaDoc m = c.getDeclaredMethod(method, paramClasses);
189         m.setAccessible(true);
190         return m.invoke(obj, params);
191     }
192
193     /**
194      * Invokes any method of a class suppressing java access checking.
195      *
196      * @param obj object to inspect
197      * @param method method to invoke
198      * @param paramClasses parameter types
199      * @param params parameters
200      */

201     public static Object JavaDoc invokeDeclared(Object JavaDoc obj, String JavaDoc method, Class JavaDoc[] paramClasses, Object JavaDoc[] params) throws IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
202         Method JavaDoc m = obj.getClass().getDeclaredMethod(method, paramClasses);
203         m.setAccessible(true);
204         return m.invoke(obj, params);
205     }
206
207     public static Object JavaDoc invokeDeclared(Object JavaDoc obj, String JavaDoc method, Object JavaDoc[] params) throws IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
208         Class JavaDoc[] paramClass = getClasses(params);
209         return invokeDeclared(obj, method, paramClass, params);
210     }
211
212     public static Object JavaDoc invokeDeclared(Class JavaDoc c, Object JavaDoc obj, String JavaDoc method, Object JavaDoc[] params) throws IllegalAccessException JavaDoc, NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
213         Class JavaDoc[] paramClass = getClasses(params);
214         return invokeDeclared(c, obj, method, paramClass, params);
215     }
216
217
218     // ---------------------------------------------------------------- match classes
219

220     /**
221      * Determines if first class match the destination and simulates kind
222      * of <code>instanceof</code>. All subclasses and interface of first class
223      * are examined against second class. Method is not symetric.
224      */

225     public static boolean isSubclass(Class JavaDoc thisClass, Class JavaDoc target) {
226         if (thisClass == target) {
227             return true;
228         }
229         if ((thisClass == null) || (target == null)){
230             return false;
231         }
232         for (Class JavaDoc x = thisClass; x != null; x = x.getSuperclass()) {
233             if (x == target) {
234                 return true;
235             }
236             if (target.isInterface() == true) {
237                 Class JavaDoc[] interfaces = x.getInterfaces();
238                 for (int i = 0; i < interfaces.length; i++) {
239                     if (isSubclass(interfaces[i], target)) {
240                         return true;
241                     }
242                 }
243             }
244         }
245         return false;
246     }
247
248     /**
249      * Dynamic version of <code>instanceof</code>.
250      * Much faster then Class.isInstance().
251      *
252      * @param o object to match
253      * @param target target class
254      * @return <code>true</code> if object is an instance of target class
255      */

256     public static boolean isInstanceOf(Object JavaDoc o, Class JavaDoc target) {
257         return isSubclass(o.getClass(), target);
258     }
259
260
261     // ---------------------------------------------------------------- accessible methods
262

263
264     /**
265      * Returns array of all methods that are accessible from given class.
266      * @see #getAccessibleMethods(Class, Class)
267      */

268     public static Method JavaDoc[] getAccessibleMethods(Class JavaDoc clazz) {
269         return getAccessibleMethods(clazz, Object JavaDoc.class);
270     }
271
272     /**
273      * Returns array of all methods that are accessible from given class, upto limit
274      * (usually <code>Object.class</code>).
275      */

276     public static Method JavaDoc[] getAccessibleMethods(Class JavaDoc clazz, Class JavaDoc limit) {
277         Package JavaDoc topPackage = clazz.getPackage();
278         List methodList = new ArrayList();
279         int topPackageHash = topPackage == null ? 0 : topPackage.hashCode();
280         boolean top = true;
281         do {
282             if (clazz == null) {
283                 break;
284             }
285             Method JavaDoc[] declaredMethods = clazz.getDeclaredMethods();
286             for (int i = 0; i < declaredMethods.length; i++) {
287                 Method JavaDoc method = declaredMethods[i];
288                 if (top == true) { // add all top declared methods
289
methodList.add(method);
290                     continue;
291                 }
292                 int modifier = method.getModifiers();
293                 if (Modifier.isPrivate(modifier) == true) {
294                     continue; // ignore super private methods
295
}
296                 if (Modifier.isAbstract(modifier) == true) { // ignore super abstract methods
297
continue;
298                 }
299                 if (Modifier.isPublic(modifier) == true) {
300                     addMethodIfNotExist(methodList, method); // add super public methods
301
continue;
302                 }
303                 if (Modifier.isProtected(modifier) == true) {
304                     addMethodIfNotExist(methodList, method); // add super protected methods
305
continue;
306                 }
307                 // add super default methods from the same package
308
Package JavaDoc pckg = method.getDeclaringClass().getPackage();
309                 int pckgHash = pckg == null ? 0 : pckg.hashCode();
310                 if (pckgHash == topPackageHash) {
311                     addMethodIfNotExist(methodList, method);
312                 }
313             }
314             top = false;
315         } while ((clazz = clazz.getSuperclass()) != limit);
316
317         Method JavaDoc[] methods = new Method JavaDoc[methodList.size()];
318         for (int i = 0; i < methods.length; i++) {
319             methods[i] = (Method JavaDoc) methodList.get(i);
320         }
321         return methods;
322     }
323
324     private static void addMethodIfNotExist(List allMethods, Method JavaDoc newMethod) {
325         for (int i = 0; i < allMethods.size(); i++) {
326             Method JavaDoc m = (Method JavaDoc) allMethods.get(i);
327             if (compareSignatures(m, newMethod) == true) {
328                 return;
329             }
330         }
331         allMethods.add(newMethod);
332     }
333
334     // ---------------------------------------------------------------- accessible fields
335

336
337     public static Field JavaDoc[] getAccessibleFields(Class JavaDoc clazz) {
338         return getAccessibleFields(clazz, Object JavaDoc.class);
339     }
340
341     public static Field JavaDoc[] getAccessibleFields(Class JavaDoc clazz, Class JavaDoc limit) {
342         Package JavaDoc topPackage = clazz.getPackage();
343         List fieldList = new ArrayList();
344         int topPackageHash = topPackage == null ? 0 : topPackage.hashCode();
345         boolean top = true;
346         do {
347             if (clazz == null) {
348                 break;
349             }
350             Field JavaDoc[] declaredFields = clazz.getDeclaredFields();
351             for (int i = 0; i < declaredFields.length; i++) {
352                 Field JavaDoc field = declaredFields[i];
353                 if (top == true) { // add all top declared fields
354
fieldList.add(field);
355                     continue;
356                 }
357                 int modifier = field.getModifiers();
358                 if (Modifier.isPrivate(modifier) == true) {
359                     continue; // ignore super private fields
360
}
361                 if (Modifier.isPublic(modifier) == true) {
362                     addFieldIfNotExist(fieldList, field); // add super public methods
363
continue;
364                 }
365                 if (Modifier.isProtected(modifier) == true) {
366                     addFieldIfNotExist(fieldList, field); // add super protected methods
367
continue;
368                 }
369                 // add super default methods from the same package
370
Package JavaDoc pckg = field.getDeclaringClass().getPackage();
371                 int pckgHash = pckg == null ? 0 : pckg.hashCode();
372                 if (pckgHash == topPackageHash) {
373                     addFieldIfNotExist(fieldList, field);
374                 }
375             }
376             top = false;
377         } while ((clazz = clazz.getSuperclass()) != limit);
378
379         Field JavaDoc[] fields = new Field JavaDoc[fieldList.size()];
380         for (int i = 0; i < fields.length; i++) {
381             fields[i] = (Field JavaDoc) fieldList.get(i);
382         }
383         return fields;
384     }
385
386     private static void addFieldIfNotExist(List allFields, Field JavaDoc newField) {
387         for (int i = 0; i < allFields.size(); i++) {
388             Field JavaDoc f = (Field JavaDoc) allFields.get(i);
389             if (compareSignatures(f, newField) == true) {
390                 return;
391             }
392         }
393         allFields.add(newField);
394     }
395
396
397     // ---------------------------------------------------------------- supported methods
398

399
400     public static Method JavaDoc[] getSupportedMethods(Class JavaDoc clazz) {
401         return getSupportedMethods(clazz, Object JavaDoc.class);
402     }
403
404     /**
405      * Returns a <code>Method</code> array of the methods to which instances of the specified
406      * respond except for those methods defined in the class specifed by limit
407      * or any of its superclasses. Note that limit is usually used to eliminate
408      * them methods defined by <code>java.lang.Object</code>. If limit is <code>null</code> then all
409      * methods are returned.
410      */

411     public static Method JavaDoc[] getSupportedMethods(Class JavaDoc clazz, Class JavaDoc limit) {
412         ArrayList supportedMethods = new ArrayList();
413         for (Class JavaDoc c = clazz; c != limit; c = c.getSuperclass()) {
414             Method JavaDoc[] methods = c.getDeclaredMethods();
415             for (int i = 0; i < methods.length; i++) {
416                 boolean found = false;
417                 for (int j = 0; j < supportedMethods.size(); j++) {
418                     if (compareSignatures(methods[i], (Method JavaDoc) supportedMethods.get(j))) {
419                         found = true;
420                         break;
421                     }
422                 }
423                 if (found == false) {
424                     supportedMethods.add(methods[i]);
425                 }
426             }
427         }
428         Method JavaDoc[] mArray = new Method JavaDoc[supportedMethods.size()];
429         for (int k = 0; k < mArray.length; k++) {
430             mArray[k] = (Method JavaDoc) supportedMethods.get(k);
431         }
432         return mArray;
433     }
434
435
436     public static Field JavaDoc[] getSupportedFields(Class JavaDoc clazz) {
437         return getSupportedFields(clazz, Object JavaDoc.class);
438     }
439
440     public static Field JavaDoc[] getSupportedFields(Class JavaDoc clazz, Class JavaDoc limit) {
441         ArrayList supportedFields = new ArrayList();
442         for (Class JavaDoc c = clazz; c != limit; c = c.getSuperclass()) {
443             Field JavaDoc[] fields = c.getDeclaredFields();
444             for (int i = 0; i < fields.length; i++) {
445                 boolean found = false;
446                 for (int j = 0; j < supportedFields.size(); j++) {
447                     if (compareSignatures(fields[i], (Field JavaDoc) supportedFields.get(j))) {
448                         found = true;
449                         break;
450                     }
451                 }
452                 if (found == false) {
453                     supportedFields.add(fields[i]);
454                 }
455             }
456         }
457         Field JavaDoc[] mArray = new Field JavaDoc[supportedFields.size()];
458         for (int k = 0; k < mArray.length; k++) {
459             mArray[k] = (Field JavaDoc) supportedFields.get(k);
460         }
461         return mArray;
462     }
463
464
465     // ---------------------------------------------------------------- compare
466

467     /**
468      * Compares method declarations: signature and return types.
469      */

470     public static boolean compareDeclarations(Method JavaDoc first, Method JavaDoc second) {
471         if (first.getReturnType() != second.getReturnType()) {
472             return false;
473         }
474         return compareSignatures(first, second);
475     }
476
477     /**
478      * Compares method signatures: names and parameters
479      */

480     public static boolean compareSignatures(Method JavaDoc first, Method JavaDoc second) {
481         if (first.getName().equals(second.getName()) == false) {
482             return false;
483         }
484         return compareParameteres(first.getParameterTypes(), second.getParameterTypes());
485     }
486
487     /**
488      * Compares constructor signatures: names and parameters
489      */

490     public static boolean compareSignatures(Constructor JavaDoc first, Constructor JavaDoc second) {
491         if (first.getName().equals(second.getName()) == false) {
492             return false;
493         }
494         return compareParameteres(first.getParameterTypes(), second.getParameterTypes());
495     }
496
497     public static boolean compareSignatures(Field JavaDoc first, Field JavaDoc second) {
498         return first.getName().equals(second.getName());
499     }
500
501
502
503     /**
504      * Comapres method or ctor parameters.
505      */

506     public static boolean compareParameteres(Class JavaDoc[] first, Class JavaDoc[] second) {
507         if (first.length != second.length) {
508             return false;
509         }
510         for (int i = 0; i < first.length; i++) {
511             if (first[i] != second[i]) {
512                 return false;
513             }
514         }
515         return true;
516     }
517
518
519
520     // ---------------------------------------------------------------- force
521

522     /**
523      * Suppress access check against a reflection object. SecurityException is silently ignored.
524      */

525     public static void forceAccess(AccessibleObject JavaDoc accObject){
526         try {
527             accObject.setAccessible(true);
528         } catch (SecurityException JavaDoc sex) {
529             // ignore
530
}
531     }
532
533     // ---------------------------------------------------------------- is public
534

535     /**
536      * Returns <code>true</code> if class member is public.
537      */

538     public static boolean isPublic(Member JavaDoc member) {
539         return Modifier.isPublic(member.getModifiers());
540     }
541
542     /**
543      * Returns <code>true</code> if class member is public and if its declaring class is also public.
544      */

545     public static boolean isPublicPublic(Member JavaDoc member) {
546         if (Modifier.isPublic(member.getModifiers()) == true) {
547             if (Modifier.isPublic(member.getDeclaringClass().getModifiers())) {
548                 return true;
549             }
550         }
551         return false;
552     }
553
554     /**
555      * Returns <code>true</code> if class is public.
556      */

557     public static boolean isPublic(Class JavaDoc c) {
558         return Modifier.isPublic(c.getModifiers());
559     }
560
561
562     // ---------------------------------------------------------------- create
563

564     private static final Object JavaDoc[] cachedInstances = {
565             new Integer JavaDoc(0),
566             "",
567             new Long JavaDoc(0),
568             new Float JavaDoc(0),
569             new Double JavaDoc(0),
570             new Byte JavaDoc((byte) 0),
571             new Short JavaDoc((short) 0),
572             new Character JavaDoc((char) 0),
573     };
574
575     /**
576      * Creates new intances including for common mutable classes that do not have a default constructor.
577      * more user-friendly. It examines if class is a map, list,
578      * String, Character, Boolean or a Number. Immutable instances are cached and not created again.
579      * Arrays are also created with no elements. Note that this bunch of ifs is faster then a hashmap.
580      */

581     public static Object JavaDoc newInstance(Class JavaDoc type) throws IllegalAccessException JavaDoc, InstantiationException JavaDoc {
582         if (type == Integer JavaDoc.class) {
583             return cachedInstances[0];
584         }
585         if (type == String JavaDoc.class) {
586             return cachedInstances[1];
587         }
588         if (type == Long JavaDoc.class) {
589             return cachedInstances[2];
590         }
591         if (type == Float JavaDoc.class) {
592             return cachedInstances[3];
593         }
594         if (type == Double JavaDoc.class) {
595             return cachedInstances[4];
596         }
597
598         if (type == Map.class) {
599             return new HashMap();
600         }
601         if (type == List.class) {
602             return new ArrayList();
603         }
604         if (type == Set.class) {
605             return new HashSet();
606         }
607
608         if (type == Byte JavaDoc.class) {
609             return cachedInstances[5];
610         }
611         if (type == Short JavaDoc.class) {
612             return cachedInstances[6];
613         }
614         if (type == Character JavaDoc.class) {
615             return cachedInstances[7];
616         }
617
618         if (type.isArray() == true) {
619             return Array.newInstance(type.getComponentType(), 0);
620         }
621
622         return type.newInstance();
623     }
624
625
626     // ---------------------------------------------------------------- misc
627

628     public static boolean isAssignableFrom(Member JavaDoc member1, Member JavaDoc member2) {
629         return member1.getDeclaringClass().isAssignableFrom(member2.getDeclaringClass());
630     }
631
632     /**
633      * Returns all superclasses.
634      */

635     public static Class JavaDoc[] getSuperclasses(Class JavaDoc type) {
636         int i = 0;
637         for (Class JavaDoc x = type.getSuperclass(); x != null; x = x.getSuperclass()) {
638             i++;
639         }
640         Class JavaDoc[] result = new Class JavaDoc[i];
641         i = 0;
642         for (Class JavaDoc x = type.getSuperclass(); x != null; x = x.getSuperclass()) {
643             result[i] = x;
644             i++;
645         }
646         return result;
647     }
648
649     /**
650      * Returns <code>true</code> if method is user defined and not defined in <code>Object</code> class.
651      */

652     public static boolean isUserDefinedMethod(final Method JavaDoc method) {
653         return method.getDeclaringClass() != Object JavaDoc.class;
654     }
655
656
657     /**
658      * Returns <code>true</code> if method is a bean property.
659      */

660     public static boolean isBeanProperty(Method JavaDoc method) {
661         String JavaDoc methodName = method.getName();
662         Class JavaDoc returnType = method.getReturnType();
663         Class JavaDoc[] paramTypes = method.getParameterTypes();
664         if (methodName.startsWith("get") && methodName.equals("getClass") == false) { // getter method must starts with 'get' and it is not getClass()
665
if ((returnType != null) && (paramTypes.length == 0)) { // getter must have a return type and no arguments
666
return true;
667             }
668         } else if (methodName.startsWith("is")) { // ister must starts with 'is'
669
if ((returnType != null) && (paramTypes.length == 0)) { // ister must have return type and no arguments
670
return true;
671             }
672         } else if (methodName.startsWith("set")) { // setter must start with a 'set'
673
if (paramTypes.length == 1) { // setter must have just one argument
674
return true;
675             }
676         }
677         return false;
678     }
679
680 }
Popular Tags