001: // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
002:
003: package jodd.util;
004:
005: import jodd.typeconverter.TypeConverter;
006: import jodd.typeconverter.TypeConverterManager;
007:
008: import java.lang.reflect.AccessibleObject;
009: import java.lang.reflect.Array;
010: import java.lang.reflect.Constructor;
011: import java.lang.reflect.Field;
012: import java.lang.reflect.GenericArrayType;
013: import java.lang.reflect.InvocationTargetException;
014: import java.lang.reflect.Member;
015: import java.lang.reflect.Method;
016: import java.lang.reflect.Modifier;
017: import java.lang.reflect.ParameterizedType;
018: import java.lang.reflect.Type;
019: import java.lang.reflect.TypeVariable;
020: import java.lang.reflect.WildcardType;
021: import java.util.ArrayList;
022: import java.util.Collection;
023: import java.util.HashMap;
024: import java.util.LinkedHashSet;
025: import java.util.List;
026: import java.util.Map;
027: import java.util.Set;
028:
029: /**
030: * Various java.lang.reflect utilities.
031: */
032: public class ReflectUtil {
033:
034: /** an empty class array */
035: public static final Class[] NO_PARAMETERS = new Class[0];
036:
037: /** an empty object array */
038: public static final Object[] NO_ARGUMENTS = new Object[0];
039:
040: /** an empty object array */
041: public static final Type[] NO_TYPES = new Type[0];
042:
043: // ---------------------------------------------------------------- method0
044:
045: private static Method _getMethod0;
046: static {
047: try {
048: _getMethod0 = Class.class.getDeclaredMethod("getMethod0",
049: String.class, Class[].class);
050: _getMethod0.setAccessible(true);
051: } catch (Exception e) {
052: try {
053: _getMethod0 = Class.class.getMethod("getMethod",
054: String.class, Class[].class);
055: } catch (Exception ex) {
056: _getMethod0 = null;
057: }
058: }
059: }
060:
061: /**
062: * Invokes private <code>Class.getMethod0()</code> without throwing NoSuchMethodException.
063: * Returns only public methods or <code>null</code> if method not found.
064: *
065: * @param c class to inspect
066: * @param name name of method to find
067: * @param parameterTypes parameter types
068: * @return founded method, or null
069: */
070: public static Method getMethod0(Class c, String name,
071: Class... parameterTypes) {
072: try {
073: return (Method) _getMethod0.invoke(c, name, parameterTypes);
074: } catch (Exception ex) {
075: return null;
076: }
077: }
078:
079: /**
080: * Invokes private <code>Class.getMethod0()</code> without throwing NoSuchMethod exception.
081: * Returns only accessible methods.
082: *
083: * @param o object to inspect
084: * @param name name of method to find
085: * @param parameterTypes parameter types
086: * @return founded method, or null
087: */
088: public static Method getMethod0(Object o, String name,
089: Class... parameterTypes) {
090: try {
091: return (Method) _getMethod0.invoke(o.getClass(), name,
092: parameterTypes);
093: } catch (Exception ex) {
094: return null;
095: }
096: }
097:
098: // ---------------------------------------------------------------- find method
099:
100: /**
101: * Returns method from an object, matched by name. This may be considered as
102: * a slow operation, since methods are matched one by one.
103: * Returns only accessible methods.
104: * Only first method is matched.
105: *
106: * @param c class to examine
107: * @param methodName Full name of the method.
108: * @return null if method not found
109: */
110: public static Method findMethod(Class c, String methodName) {
111: return findDeclaredMethod(c, methodName, true);
112: }
113:
114: public static Method findDeclaredMethod(Class c, String methodName) {
115: return findDeclaredMethod(c, methodName, false);
116: }
117:
118: private static Method findDeclaredMethod(Class c,
119: String methodName, boolean publicOnly) {
120: if ((methodName == null) || (c == null)) {
121: return null;
122: }
123: Method[] ms = publicOnly ? c.getMethods() : c
124: .getDeclaredMethods();
125: for (Method m : ms) {
126: if (m.getName().equals(methodName)) {
127: return m;
128: }
129: }
130: return null;
131:
132: }
133:
134: // ---------------------------------------------------------------- classes
135:
136: /**
137: * Returns classes from array of specified objects.
138: */
139: public static Class[] getClasses(Object... objects) {
140: if (objects == null) {
141: return null;
142: }
143: Class[] result = new Class[objects.length];
144: for (int i = 0; i < objects.length; i++) {
145: if (objects[i] != null) {
146: result[i] = objects[i].getClass();
147: }
148: }
149: return result;
150: }
151:
152: // ---------------------------------------------------------------- invoke
153:
154: /**
155: * Invokes accessible method of an object.
156: *
157: * @param c class that contains method
158: * @param obj object to execute
159: * @param method method to invoke
160: * @param paramClasses classes of parameters
161: * @param params parameters
162: � */
163: public static Object invoke(Class c, Object obj, String method,
164: Class[] paramClasses, Object[] params)
165: throws IllegalAccessException, NoSuchMethodException,
166: InvocationTargetException {
167: Method m = c.getMethod(method, paramClasses);
168: return m.invoke(obj, params);
169: }
170:
171: /**
172: * Invokes accessible method of an object.
173: *
174: * @param obj object
175: * @param method name of the objects method
176: * @param params method parameters
177: * @param paramClasses method parameter types
178: */
179: public static Object invoke(Object obj, String method,
180: Class[] paramClasses, Object[] params)
181: throws IllegalAccessException, NoSuchMethodException,
182: InvocationTargetException {
183: Method m = obj.getClass().getMethod(method, paramClasses);
184: return m.invoke(obj, params);
185: }
186:
187: /**
188: * Invokes accessible method of an object without specifying parameter types.
189: * @param obj object
190: * @param method method of an object
191: * @param params method parameters
192: */
193: public static Object invoke(Object obj, String method,
194: Object[] params) throws IllegalAccessException,
195: NoSuchMethodException, InvocationTargetException {
196: Class[] paramClass = getClasses(params);
197: return invoke(obj, method, paramClass, params);
198: }
199:
200: public static Object invoke(Class c, Object obj, String method,
201: Object[] params) throws IllegalAccessException,
202: NoSuchMethodException, InvocationTargetException {
203: Class[] paramClass = getClasses(params);
204: return invoke(c, obj, method, paramClass, params);
205: }
206:
207: // ---------------------------------------------------------------- invokeDeclared
208:
209: /**
210: * Invokes any method of a class, even private ones.
211: *
212: * @param c class to examine
213: * @param obj object to inspect
214: * @param method method to invoke
215: * @param paramClasses parameter types
216: * @param params parameters
217: */
218: public static Object invokeDeclared(Class c, Object obj,
219: String method, Class[] paramClasses, Object[] params)
220: throws IllegalAccessException, NoSuchMethodException,
221: InvocationTargetException {
222: Method m = c.getDeclaredMethod(method, paramClasses);
223: m.setAccessible(true);
224: return m.invoke(obj, params);
225: }
226:
227: /**
228: * Invokes any method of a class suppressing java access checking.
229: *
230: * @param obj object to inspect
231: * @param method method to invoke
232: * @param paramClasses parameter types
233: * @param params parameters
234: */
235: public static Object invokeDeclared(Object obj, String method,
236: Class[] paramClasses, Object[] params)
237: throws IllegalAccessException, NoSuchMethodException,
238: InvocationTargetException {
239: Method m = obj.getClass().getDeclaredMethod(method,
240: paramClasses);
241: m.setAccessible(true);
242: return m.invoke(obj, params);
243: }
244:
245: public static Object invokeDeclared(Object obj, String method,
246: Object[] params) throws IllegalAccessException,
247: NoSuchMethodException, InvocationTargetException {
248: Class[] paramClass = getClasses(params);
249: return invokeDeclared(obj, method, paramClass, params);
250: }
251:
252: public static Object invokeDeclared(Class c, Object obj,
253: String method, Object[] params)
254: throws IllegalAccessException, NoSuchMethodException,
255: InvocationTargetException {
256: Class[] paramClass = getClasses(params);
257: return invokeDeclared(c, obj, method, paramClass, params);
258: }
259:
260: // ---------------------------------------------------------------- match classes
261:
262: /**
263: * Determines if first class match the destination and simulates kind
264: * of <code>instanceof</code>. All subclasses and interface of first class
265: * are examined against second class. Method is not symetric.
266: */
267: public static boolean isSubclass(Class this Class, Class target) {
268: if (this Class == target) {
269: return true;
270: }
271: if ((this Class == null) || (target == null)) {
272: return false;
273: }
274: for (Class x = this Class; x != null; x = x.getSuperclass()) {
275: if (x == target) {
276: return true;
277: }
278: if (target.isInterface() == true) {
279: Class[] interfaces = x.getInterfaces();
280: for (Class anInterface : interfaces) {
281: if (isSubclass(anInterface, target)) {
282: return true;
283: }
284: }
285: }
286: }
287: return false;
288: }
289:
290: /**
291: * Dynamic version of <code>instanceof</code>.
292: * Much faster then Class.isInstance().
293: *
294: * @param o object to match
295: * @param target target class
296: * @return <code>true</code> if object is an instance of target class
297: */
298: public static boolean isInstanceOf(Object o, Class target) {
299: return isSubclass(o.getClass(), target);
300: }
301:
302: /**
303: * Casts an object to destination type using type conversion if available.
304: */
305: public static Object castType(Object value, Class destinationType) {
306: if ((value != null)
307: && (isInstanceOf(value, destinationType) == false)) {
308: TypeConverter converter = TypeConverterManager
309: .lookup(destinationType);
310: if (converter == null) {
311: throw new ClassCastException("Unable to cast value '"
312: + value + "' to type: '" + destinationType
313: + "'.");
314: }
315: return converter.convert(value);
316: }
317: return value;
318: }
319:
320: // ---------------------------------------------------------------- accessible methods
321:
322: /**
323: * Returns array of all methods that are accessible from given class.
324: * @see #getAccessibleMethods(Class, Class)
325: */
326: public static Method[] getAccessibleMethods(Class clazz) {
327: return getAccessibleMethods(clazz, Object.class);
328: }
329:
330: /**
331: * Returns array of all methods that are accessible from given class, upto limit
332: * (usually <code>Object.class</code>).
333: */
334: public static Method[] getAccessibleMethods(Class clazz, Class limit) {
335: Package topPackage = clazz.getPackage();
336: List<Method> methodList = new ArrayList<Method>();
337: int topPackageHash = topPackage == null ? 0 : topPackage
338: .hashCode();
339: boolean top = true;
340: do {
341: if (clazz == null) {
342: break;
343: }
344: Method[] declaredMethods = clazz.getDeclaredMethods();
345: for (Method method : declaredMethods) {
346: if (top == true) { // add all top declared methods
347: methodList.add(method);
348: continue;
349: }
350: int modifier = method.getModifiers();
351: if (Modifier.isPrivate(modifier) == true) {
352: continue; // ignore super private methods
353: }
354: if (Modifier.isAbstract(modifier) == true) { // ignore super abstract methods
355: continue;
356: }
357: if (Modifier.isPublic(modifier) == true) {
358: addMethodIfNotExist(methodList, method); // add super public methods
359: continue;
360: }
361: if (Modifier.isProtected(modifier) == true) {
362: addMethodIfNotExist(methodList, method); // add super protected methods
363: continue;
364: }
365: // add super default methods from the same package
366: Package pckg = method.getDeclaringClass().getPackage();
367: int pckgHash = pckg == null ? 0 : pckg.hashCode();
368: if (pckgHash == topPackageHash) {
369: addMethodIfNotExist(methodList, method);
370: }
371: }
372: top = false;
373: } while ((clazz = clazz.getSuperclass()) != limit);
374:
375: Method[] methods = new Method[methodList.size()];
376: for (int i = 0; i < methods.length; i++) {
377: methods[i] = methodList.get(i);
378: }
379: return methods;
380: }
381:
382: private static void addMethodIfNotExist(List<Method> allMethods,
383: Method newMethod) {
384: for (Method m : allMethods) {
385: if (compareSignatures(m, newMethod) == true) {
386: return;
387: }
388: }
389: allMethods.add(newMethod);
390: }
391:
392: // ---------------------------------------------------------------- accessible fields
393:
394: public static Field[] getAccessibleFields(Class clazz) {
395: return getAccessibleFields(clazz, Object.class);
396: }
397:
398: public static Field[] getAccessibleFields(Class clazz, Class limit) {
399: Package topPackage = clazz.getPackage();
400: List<Field> fieldList = new ArrayList<Field>();
401: int topPackageHash = topPackage == null ? 0 : topPackage
402: .hashCode();
403: boolean top = true;
404: do {
405: if (clazz == null) {
406: break;
407: }
408: Field[] declaredFields = clazz.getDeclaredFields();
409: for (Field field : declaredFields) {
410: if (top == true) { // add all top declared fields
411: fieldList.add(field);
412: continue;
413: }
414: int modifier = field.getModifiers();
415: if (Modifier.isPrivate(modifier) == true) {
416: continue; // ignore super private fields
417: }
418: if (Modifier.isPublic(modifier) == true) {
419: addFieldIfNotExist(fieldList, field); // add super public methods
420: continue;
421: }
422: if (Modifier.isProtected(modifier) == true) {
423: addFieldIfNotExist(fieldList, field); // add super protected methods
424: continue;
425: }
426: // add super default methods from the same package
427: Package pckg = field.getDeclaringClass().getPackage();
428: int pckgHash = pckg == null ? 0 : pckg.hashCode();
429: if (pckgHash == topPackageHash) {
430: addFieldIfNotExist(fieldList, field);
431: }
432: }
433: top = false;
434: } while ((clazz = clazz.getSuperclass()) != limit);
435:
436: Field[] fields = new Field[fieldList.size()];
437: for (int i = 0; i < fields.length; i++) {
438: fields[i] = fieldList.get(i);
439: }
440: return fields;
441: }
442:
443: private static void addFieldIfNotExist(List<Field> allFields,
444: Field newField) {
445: for (Field f : allFields) {
446: if (compareSignatures(f, newField) == true) {
447: return;
448: }
449: }
450: allFields.add(newField);
451: }
452:
453: // ---------------------------------------------------------------- supported methods
454:
455: public static Method[] getSupportedMethods(Class clazz) {
456: return getSupportedMethods(clazz, Object.class);
457: }
458:
459: /**
460: * Returns a <code>Method</code> array of the methods to which instances of the specified
461: * respond except for those methods defined in the class specifed by limit
462: * or any of its superclasses. Note that limit is usually used to eliminate
463: * them methods defined by <code>java.lang.Object</code>. If limit is <code>null</code> then all
464: * methods are returned.
465: */
466: public static Method[] getSupportedMethods(Class clazz, Class limit) {
467: ArrayList<Method> supportedMethods = new ArrayList<Method>();
468: for (Class c = clazz; c != limit; c = c.getSuperclass()) {
469: Method[] methods = c.getDeclaredMethods();
470: for (Method method : methods) {
471: boolean found = false;
472: for (Method supportedMethod : supportedMethods) {
473: if (compareSignatures(method, supportedMethod)) {
474: found = true;
475: break;
476: }
477: }
478: if (found == false) {
479: supportedMethods.add(method);
480: }
481: }
482: }
483: return supportedMethods.toArray(new Method[supportedMethods
484: .size()]);
485: }
486:
487: public static Field[] getSupportedFields(Class clazz) {
488: return getSupportedFields(clazz, Object.class);
489: }
490:
491: public static Field[] getSupportedFields(Class clazz, Class limit) {
492: ArrayList<Field> supportedFields = new ArrayList<Field>();
493: for (Class c = clazz; c != limit; c = c.getSuperclass()) {
494: Field[] fields = c.getDeclaredFields();
495: for (Field field : fields) {
496: boolean found = false;
497: for (Field supportedField : supportedFields) {
498: if (compareSignatures(field, supportedField)) {
499: found = true;
500: break;
501: }
502: }
503: if (found == false) {
504: supportedFields.add(field);
505: }
506: }
507: }
508: return supportedFields
509: .toArray(new Field[supportedFields.size()]);
510: }
511:
512: // ---------------------------------------------------------------- compare
513:
514: /**
515: * Compares method declarations: signature and return types.
516: */
517: public static boolean compareDeclarations(Method first,
518: Method second) {
519: if (first.getReturnType() != second.getReturnType()) {
520: return false;
521: }
522: return compareSignatures(first, second);
523: }
524:
525: /**
526: * Compares method signatures: names and parameters
527: */
528: public static boolean compareSignatures(Method first, Method second) {
529: if (first.getName().equals(second.getName()) == false) {
530: return false;
531: }
532: return compareParameteres(first.getParameterTypes(), second
533: .getParameterTypes());
534: }
535:
536: /**
537: * Compares constructor signatures: names and parameters
538: */
539: public static boolean compareSignatures(Constructor first,
540: Constructor second) {
541: if (first.getName().equals(second.getName()) == false) {
542: return false;
543: }
544: return compareParameteres(first.getParameterTypes(), second
545: .getParameterTypes());
546: }
547:
548: public static boolean compareSignatures(Field first, Field second) {
549: return first.getName().equals(second.getName());
550: }
551:
552: /**
553: * Comapres method or ctor parameters.
554: */
555: public static boolean compareParameteres(Class[] first,
556: Class[] second) {
557: if (first.length != second.length) {
558: return false;
559: }
560: for (int i = 0; i < first.length; i++) {
561: if (first[i] != second[i]) {
562: return false;
563: }
564: }
565: return true;
566: }
567:
568: // ---------------------------------------------------------------- force
569:
570: /**
571: * Suppress access check against a reflection object. SecurityException is silently ignored.
572: */
573: public static void forceAccess(AccessibleObject accObject) {
574: try {
575: accObject.setAccessible(true);
576: } catch (SecurityException sex) {
577: // ignore
578: }
579: }
580:
581: // ---------------------------------------------------------------- is public
582:
583: /**
584: * Returns <code>true</code> if class member is public.
585: */
586: public static boolean isPublic(Member member) {
587: return Modifier.isPublic(member.getModifiers());
588: }
589:
590: /**
591: * Returns <code>true</code> if class member is public and if its declaring class is also public.
592: */
593: public static boolean isPublicPublic(Member member) {
594: if (Modifier.isPublic(member.getModifiers()) == true) {
595: if (Modifier.isPublic(member.getDeclaringClass()
596: .getModifiers())) {
597: return true;
598: }
599: }
600: return false;
601: }
602:
603: /**
604: * Returns <code>true</code> if class is public.
605: */
606: public static boolean isPublic(Class c) {
607: return Modifier.isPublic(c.getModifiers());
608: }
609:
610: // ---------------------------------------------------------------- create
611:
612: /**
613: * Instantiates a new class.
614: */
615: public static <T> T instantiate(Class<T> clazz)
616: throws IllegalAccessException, InstantiationException {
617: return clazz.newInstance();
618: }
619:
620: /**
621: * Creates new intances including for common mutable classes that do not have a default constructor.
622: * more user-friendly. It examines if class is a map, list,
623: * String, Character, Boolean or a Number. Immutable instances are cached and not created again.
624: * Arrays are also created with no elements. Note that this bunch of ifs is faster then a hashmap.
625: */
626: public static Object newInstance(Class type)
627: throws IllegalAccessException, InstantiationException {
628: if (type == Integer.class) {
629: return Integer.valueOf(0);
630: }
631: if (type == String.class) {
632: return "";
633: }
634: if (type == Long.class) {
635: return Long.valueOf(0);
636: }
637: if (type == Float.class) {
638: Float.valueOf(0);
639: }
640: if (type == Double.class) {
641: Double.valueOf(0);
642: }
643:
644: if (type == Map.class) {
645: return new HashMap();
646: }
647: if (type == List.class) {
648: return new ArrayList();
649: }
650: if (type == Set.class) {
651: return new LinkedHashSet();
652: }
653: if (type == Collection.class) {
654: return new ArrayList();
655: }
656:
657: if (type == Byte.class) {
658: return Byte.valueOf((byte) 0);
659: }
660: if (type == Short.class) {
661: return Short.valueOf((short) 0);
662: }
663: if (type == Character.class) {
664: return Character.valueOf((char) 0);
665: }
666:
667: if (type.isArray() == true) {
668: return Array.newInstance(type.getComponentType(), 0);
669: }
670:
671: return type.newInstance();
672: }
673:
674: // ---------------------------------------------------------------- misc
675:
676: public static boolean isAssignableFrom(Member member1,
677: Member member2) {
678: return member1.getDeclaringClass().isAssignableFrom(
679: member2.getDeclaringClass());
680: }
681:
682: /**
683: * Returns all superclasses.
684: */
685: public static Class[] getSuperclasses(Class type) {
686: int i = 0;
687: for (Class x = type.getSuperclass(); x != null; x = x
688: .getSuperclass()) {
689: i++;
690: }
691: Class[] result = new Class[i];
692: i = 0;
693: for (Class x = type.getSuperclass(); x != null; x = x
694: .getSuperclass()) {
695: result[i] = x;
696: i++;
697: }
698: return result;
699: }
700:
701: /**
702: * Returns <code>true</code> if method is user defined and not defined in <code>Object</code> class.
703: */
704: public static boolean isUserDefinedMethod(final Method method) {
705: return method.getDeclaringClass() != Object.class;
706: }
707:
708: /**
709: * Returns <code>true</code> if method is a bean property.
710: */
711: public static boolean isBeanProperty(Method method) {
712: String methodName = method.getName();
713: Class returnType = method.getReturnType();
714: Class[] paramTypes = method.getParameterTypes();
715: if (methodName.startsWith("get")
716: && methodName.equals("getClass") == false) { // getter method must starts with 'get' and it is not getClass()
717: if ((returnType != null) && (paramTypes.length == 0)) { // getter must have a return type and no arguments
718: return true;
719: }
720: } else if (methodName.startsWith("is")) { // ister must starts with 'is'
721: if ((returnType != null) && (paramTypes.length == 0)) { // ister must have return type and no arguments
722: return true;
723: }
724: } else if (methodName.startsWith("set")) { // setter must start with a 'set'
725: if (paramTypes.length == 1) { // setter must have just one argument
726: return true;
727: }
728: }
729: return false;
730: }
731:
732: // ---------------------------------------------------------------- generics
733:
734: public static Class getComponentType(Type type) {
735: return getComponentType(type, 0);
736: }
737:
738: /**
739: * Returns the component type of the given <code>type</code>.<br>
740: * For example the following types all have the component-type MyClass:
741: * <ul>
742: * <li>MyClass[]</li>
743: * <li>List<MyClass></li>
744: * <li>Foo<? extends MyClass></li>
745: * <li>Bar<? super MyClass></li>
746: * <li><T extends MyClass> T[]</li>
747: * </ul>
748: *
749: * @param type is the type where to get the component type from.
750: * @return the component type of the given <code>type</code> or
751: * <code>null</code> if the given <code>type</code> does NOT have
752: * a single (component) type.
753: */
754: public static Class getComponentType(Type type, int index) {
755: if (type instanceof Class) {
756: Class clazz = (Class) type;
757: if (clazz.isArray()) {
758: return clazz.getComponentType();
759: }
760: } else if (type instanceof ParameterizedType) {
761: ParameterizedType pt = (ParameterizedType) type;
762: Type[] generics = pt.getActualTypeArguments();
763: if (generics.length >= index + 1) {
764: return toClass(generics[index]);
765: }
766: } else if (type instanceof GenericArrayType) {
767: GenericArrayType gat = (GenericArrayType) type;
768: return toClass(gat.getGenericComponentType());
769: }
770: return null;
771: }
772:
773: /**
774: * Returmns {@link Class} for the given <code>type</code>.<br>
775: * Examples: <br>
776: * <table border="1">
777: * <tr>
778: * <th><code>type</code></th>
779: * <th><code>{@link #toClass(Type) getSimpleType}(type)</code></th>
780: * </tr>
781: * <tr>
782: * <td><code>String</code></td>
783: * <td><code>String</code></td>
784: * </td>
785: * <tr>
786: * <td><code>List<String></code></td>
787: * <td><code>List</code></td>
788: * </td>
789: * <tr>
790: * <td><code><T extends MyClass> T[]</code></td>
791: * <td><code>MyClass[]</code></td>
792: * </td>
793: * </table>
794: *
795: * @param type is the type to convert.
796: * @return the closest class representing the given <code>type</code>.
797: */
798: public static Class toClass(Type type) {
799: if (type instanceof Class) {
800: return (Class) type;
801: } else if (type instanceof ParameterizedType) {
802: ParameterizedType pt = (ParameterizedType) type;
803: return toClass(pt.getRawType());
804: } else if (type instanceof WildcardType) {
805: WildcardType wt = (WildcardType) type;
806: Type[] lower = wt.getLowerBounds();
807: if (lower.length == 1) {
808: return toClass(lower[0]);
809: }
810: Type[] upper = wt.getUpperBounds();
811: if (upper.length == 1) {
812: return toClass(upper[0]);
813: }
814: } else if (type instanceof GenericArrayType) {
815: GenericArrayType gat = (GenericArrayType) type;
816: Class componentType = toClass(gat.getGenericComponentType());
817: // this is sort of stupid but there seems no other way...
818: return Array.newInstance(componentType, 0).getClass();
819: } else if (type instanceof TypeVariable) {
820: TypeVariable tv = (TypeVariable) type;
821: Type[] bounds = tv.getBounds();
822: if (bounds.length == 1) {
823: return toClass(bounds[0]);
824: }
825: }
826: return null;
827: }
828:
829: }
|