View Javadoc
1   
2   package eu.simuline.testhelpers;
3   
4   import eu.simuline.util.BasicTypesCompatibilityChecker;
5   
6   import java.lang.reflect.Modifier;
7   import java.lang.reflect.Constructor;
8   import java.lang.reflect.Method;
9   import java.lang.reflect.Field;
10  import java.lang.reflect.InvocationTargetException;
11  
12  /**
13   * Provides access even to private fields, methods, constructors 
14   * and inner classes, static or not, via reflection. 
15   * This is necessary for white-box-tests. 
16   * Note that class objects for instances <code>i</code> 
17   * are given by <code>i.getClass()</code> 
18   *(except for instances of primitive types) 
19   * but also if no instance is available, 
20   * the class object is given by 
21   * <ul>
22   * <li>
23   * <code>&lt;classname&gt;.class</code> for all types even the primitive ones 
24   * and also for arrays 
25   * (<code>int.class</code> and <code>int[].class</code> are valid) 
26   * but not for hidden inner classes, e.g. <code>private</code> ones, 
27   * <li>
28   * <code>Boolean.TYPE</code>, 
29   * <code>Character.TYPE</code> and so on for the primitive types 
30   * (which is superfluous because <code>boolean.class</code> 
31   * works as well as <code>Boolean.TYPE</code>, 
32   * except for <code>java.lang.Void.TYPE</code> which I never used so far), 
33   * <li>
34   * methods {@link #getInnerClass(Class,String)} and 
35   * {@link #getInnerClass(Class,String[])} for hidden inner classes. 
36   * Note that formally this even works for anonymous classes 
37   * but since names of anonymous classes may change 
38   * if another anonymous inner class is inserted, 
39   * this feature should be used with caution. 
40   * I personally feel it is best not to use it at all. 
41   * </ul>
42   * Avoid using <code>Class.forName(String className)</code>. 
43   * <p>
44   * The method {@link #getField(Class,String)} 
45   * returns the value of the specified static field. 
46   * Note that if the field has primitive type, 
47   * the wrapper of its content is returned. 
48   * Correspondingly, {@link #getField(Object,String)} 
49   * returns the specified instant field. 
50   * Note that since the class <code>Class</code> is final, 
51   * and has no (non-public) fields, there should be no reason, 
52   * to access a <code>Class</code>-object. 
53   * In case of a very special application, 
54   * casts like <code>getField((Object)ls,name)</code> 
55   * should resolve the ambiguity. 
56   * The two methods described above, should cover the typical situations. 
57   * In some special cases however, 
58   * including overwritten fields and fields of inner classes, 
59   * {@link #getField(Class,Object,String)} 
60   * may provide the only way to access a field. 
61   * <p>
62   * What can be said about the methods <code>getField</code> 
63   * applies correspondingly to methods <code>setField</code>. 
64   * Note that there is no way to change fields 
65   * which are declared <code>final</code>. 
66   * To be more precise, the pointer in a final field 
67   * <p>
68   * Similarly for invoking methods: 
69   * Except for very special cases, 
70   * {@link #invokeStatic(Class,String,Object...)} for static methods and 
71   * {@link #invoke(Object,String,Object...)} for instance methods 
72   * will be sufficient, but for some special cases 
73   * including overwriting and inner classes 
74   * {@link #invoke(Class,Object,String,Object...)} 
75   * may be the only way to invoke a method. 
76   * Note that these methods apply to parameters with primitive types as well 
77   * by passing the appropriate wrapper object: 
78   * For example <code>Integer.toString(int i)</code> may be invoked by 
79   * <code>invoke(Integer.class,"toString",new Integer(i))</code>. 
80   * <p>
81   * Still there is a problem: 
82   * if wrapping parameters makes signatures ambiguous, 
83   * the parameter types must be specified explicitly 
84   * using method {@link #invoke(Class,Object,String,Class[],Object[])}. 
85   * For this case, which seems to be quite rare, 
86   * there are no convenience methods. 
87   * <p>
88   * Note that the return type is always <code>Object</code>. 
89   * Of course, the return value may be casted 
90   * to the return type of the specified method, 
91   * provided the return type is an object and 
92   * neither void nor a primitive type. 
93   * In the latter case, the return value is wrapped in the corresponding 
94   * wrapper class unlike the parameters. 
95   * <p>
96   * For the last case, creating objects using constructors, 
97   * in most cases {@link #create(Class,Object[])} is sufficient; 
98   * to avoid ambiguities, one has to specify the types of the parameters 
99   * and use {@link #create(Class,Class[],Object[])} instead. 
100  *
101  * @param <T>
102  *    parameter representing the class to be accessed. 
103  *
104  * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
105  * @version 1.0
106  */
107 public final class Accessor<T> {
108 
109     /* -------------------------------------------------------------------- *
110      * constants.                                                           *
111      * -------------------------------------------------------------------- */
112 
113     /**
114      * The separator between a class and its enclosing class 
115      * for inner classes. 
116      */
117     private static final String INNER_SEPARATOR = "$";
118 
119     /**
120      * String denoting an unspecified class. 
121      * This is needed for producing output only. 
122      *
123      * @see #paramsToString
124      */
125     private static final String UNSPECIFIED_CLASS = "<unspecified class>";
126 
127     // several string literals occurring more than once. 
128     private static final String STR_DNE = " does not exist. ";
129     private static final String STR_IN_CLS = "' in class '";
130     private static final String STR_SPEC_NULL_CLS = "Specified null-class. ";
131 
132     /* -------------------------------------------------------------------- *
133      * private constructor.                                                 *
134      * -------------------------------------------------------------------- */
135 
136     /**
137      * Formally to create a new <code>Accessor</code> instance 
138      * but intended in contrary 
139      * to prevent an <code>Accessor</code> from being instantiated. 
140      * Note that the modifiers <code>final</code> and <code>abstract</code> 
141      * are mutually exclusive 
142      * and so this trick is the only remaining possibility. 
143      */
144     private Accessor() {
145     }
146 
147     /* -------------------------------------------------------------------- *
148      * private methods.                                                     *
149      * -------------------------------------------------------------------- */
150 
151     /**
152      * Converts a list of classes into their string-representation. 
153      *
154      * @param paramCls 
155      *    an array of <code>Class</code>es. 
156      *    The entries in the array may well be <code>null</code>. 
157      * @return 
158      *    a comma separated sequence of the classes given. 
159      */
160     private static String paramsToString(Class<?>... paramCls) {
161 	StringBuffer ret = new StringBuffer();
162 	String clsString;
163 	ret.append('(');
164 	if (paramCls.length != 0) {
165 	    clsString = paramCls[0] == null 
166 		?  UNSPECIFIED_CLASS
167 		: paramCls[0].getName(); 
168 	    ret.append(clsString);
169 	    for (int i = 1; i < paramCls.length; i++) {
170 		ret.append(", ");
171 		clsString = paramCls[i] == null 
172 		    ?  UNSPECIFIED_CLASS
173 		    : paramCls[i].getName(); 
174 		ret.append(clsString);
175 	    }
176 	}
177 	ret.append(')');
178 	return ret.toString();
179     }
180 
181     /**
182      * Invokes the specified method with the given parameters 
183      * and returns the value (which may be void of course. ) 
184      *
185      * @param method 
186      *    a <code>Method</code>. 
187      * @param target 
188      *    the target to which the specified method is to be applied. 
189      *    the target <em>must</em> be <code>null</code>
190      *    if and only if the method specified is static. 
191      * @param parameters 
192      *    the list of parameters used when invoking <code>method</code>. 
193      *    Note that parameters of elementary types 
194      *    have to be wrapped in an object 
195      *    (e.g. write <code>new Integer(8)</code> 
196      *    instead of just <code>8</code>). 
197      * @return 
198      *    The result of invoking the specified method 
199      *    with the given parameters. 
200      *    If the method has no return value, <code>null</code> is returned. 
201      * @throws IllegalArgumentException
202      *    <ul>
203      *    <li>
204      *    if the specified method is static but <code>target != null</code>. 
205      *    <li>
206      *    if the specified method is a member method 
207      *    but <code>target == null</code>. 
208      *    </ul>
209      * @throws IllegalStateException 
210      *    with message "Method should be accessible; still is not. " 
211      *    if the method is not accessible. 
212      * @throws InvocationTargetException 
213      *   to wrap an exception thrown by the method invoked. 
214      *   Unwrap it using {@link Throwable#getCause}. 
215      */
216     private static Object invoke(Method method, 
217 				 Object target,
218 				 Object... parameters) 
219 	throws InvocationTargetException {
220 
221 	if (Modifier.isStatic(method.getModifiers()) != 
222 	    (target == null)) {
223 	    if (Modifier.isStatic(method.getModifiers())) {
224 		throw new IllegalArgumentException
225 		    ("For static method " + method.getName() + 
226 		     " no target has to be provided (i.e. null). ");
227 	    } else {
228 		throw new IllegalArgumentException
229 		    ("For member method " + method.getName() + 
230 		     " a target has to be provided (not null). ");
231 	    }
232 	}
233 
234 	try {
235 	    return method.invoke(target, parameters);
236 	} catch (IllegalAccessException ie) {
237 	    throw new IllegalStateException// NOPMD
238 		("Method should be accessible; still is not. "); 
239 	}
240     }
241 
242     /**
243      * Returns the classes of the given parameters. 
244      *
245      * @param parameters 
246      *    a parameter list represented as an array of <code>Object</code>s. 
247      * @return 
248      *    the classes of the given parameters. 
249      *    For a <code>null</code>-parameter, 
250      *    the <code>null</code>-class is returned. 
251      */
252     private static Class<?>[] getParamCls(Object... parameters) {
253 	Class<?>[] paramCls = new Class<?>[parameters.length];
254 	for (int i = 0; i < parameters.length; i++) {
255 	    paramCls[i] = parameters[i] == null 
256 		? null 
257 		: parameters[i].getClass();
258 	}
259 	return paramCls;
260     }
261 
262     /*----------------------------------------------------------------------*
263      * methods for public access.                                           *
264      *----------------------------------------------------------------------*/
265 
266     /*----------------------------------------------------------------------*
267      * getField methods                                                     *
268      *----------------------------------------------------------------------*/
269 
270     /**
271      * Returns the value of the specified member field resp. its wrapper. 
272      *
273      * @param target 
274      *    the instance for which a field is to be accessed. 
275      * @param fieldName 
276      *     the name of the field. 
277      * @return 
278      *    If the type of the specified field is <code>Object</code>, 
279      *    this object is returned directly; 
280      *    otherwise the value of the field is wrapped 
281      *    in an object of the appropriate class. 
282      *    E.g. <code>new Integer(5)</code> is returned 
283      *    instead of the <code>int</code>-value <code>5</code>. 
284      * @throws NoSuchFieldException
285      *    if the specified object 
286      *    does not contain a field with the given name, 
287      *    e.g. because <code>fieldName == null</code>. 
288      * @throws IllegalArgumentException
289      *    if the target is <code>null</code> 
290      *    or if the specified field is static. 
291      * @see #setField(Object, String, Object)
292      */
293     public static Object getField(Object target,
294 				  String fieldName) 
295 	throws NoSuchFieldException {
296 
297 	if (target == null) {
298 	    throw new IllegalArgumentException
299 		("Specified null-target. ");
300 	}
301 
302 	return getField(target.getClass(), target, fieldName);
303     }
304 
305     /**
306      * Returns the value of the specified static field resp. its wrapper. 
307      *
308      * @param aClass 
309      *    the class for which a static field is to be accessed. 
310      *    Typically one will use the expression 
311      *    <code>&lt;classname&gt;.class</code> to determine the class-object. 
312      * @param fieldName 
313      *     the name of the field. 
314      * @return 
315      *    If the value of the specified field is an Object, 
316      *    this object is returned directly; 
317      *    otherwise the value of the field is wrapped 
318      *    in an object of the appropriate class. 
319      *    E.g. <code>new Integer(5)</code> is returned 
320      *    instead of the <code>int</code>-value <code>5</code>. 
321      * @throws NoSuchFieldException
322      *    if the specified class 
323      *    does not contain a field with the given name, 
324      *    e.g. because <code>fieldName == null</code>. 
325      * @throws IllegalArgumentException
326      *    if the class-parameter is <code>null</code> 
327      *    or if the specified field is not static. 
328      * @see #setField(Class, String, Object)
329      */
330     public static Object getField(Class<?> aClass,
331 				  String fieldName) 
332 	throws NoSuchFieldException {
333 
334 	return getField(aClass, null, fieldName);
335     }
336 
337     /**
338      * Returns the specified <code>Field</code> object if possible. 
339      * This method is commonly used by the methods 
340      * named <code>getField</code> and <code>setField</code>. 
341      *
342      * @param aClass 
343      *    a <code>Class</code> object. 
344      *    Typically one will use the expression 
345      *    <code>&lt;classname&gt;.class</code> 
346      *    to determine the class-object. 
347      * @param fieldName 
348      *    the name of a field to look for in the specified class 
349      *    and its superclasses. 
350      * @param shouldBeStatic
351      *    whether the specified field should static. 
352      * @return 
353      *    the specified <code>Field</code> object 
354      *    (Should never return <code>null</code>) 
355      *    made accessible if it exists. 
356      * @throws IllegalArgumentException
357      *    if the "<code>null</code>-class" is specified. 
358      * @throws NoSuchFieldException
359      *    if the specified class and none of its superclasses
360      *    containd a field with the given name, 
361      *    e.g. because <code>fieldName == null</code>. 
362      */
363     private static Field getFieldObj(Class<?> aClass,
364 				     String fieldName,
365 				     boolean shouldBeStatic) 
366 	throws NoSuchFieldException {
367 
368 	if (aClass == null) {
369 	    throw new IllegalArgumentException(STR_SPEC_NULL_CLS);
370 	}
371 
372 	Field[] cands;
373 	Class<?> candClass = aClass;
374 
375 	do {
376 	    // look for the specified field in candClass. 
377 	    cands = candClass.getDeclaredFields();
378 	    for (int i = 0; i < cands.length; i++) {
379 		if (cands[i].getName().equals(fieldName)) {
380 		    cands[i].setAccessible(true);
381 		    // Here, aField is not null 
382 		    // (if no field: Exception thrown). 
383 
384 		    if (shouldBeStatic != 
385 			Modifier.isStatic(cands[i].getModifiers())) {
386 			throw new IllegalArgumentException
387 			    ("The specified field '" + fieldName + 
388 			     "' should " + 
389 			     (shouldBeStatic ? "" : "not ") + 
390 			     "be static. ");
391 		    }
392 
393 		    return cands[i];
394 		}
395 	    }
396 	    // Here, no such field is found. 
397 
398 	    // prepare search in superclass. 
399 	    candClass = candClass.getSuperclass();
400 	} while (candClass != null);
401 	// Here, the specified field is not found. 
402 
403 	// throws a NoSuchFieldException
404 	aClass.getDeclaredField(fieldName);
405 	throw new IllegalStateException
406 	    ("Should throw a NoSuchFieldException. ");
407     }
408 
409     /**
410      * Returns the value of the specified static field 
411      * or member field resp. its wrapper. 
412      * Use {@link #getField(Class, String)} or 
413      * {@link #getField(Object, String)} if possible. 
414      *
415      * @param aClass 
416      *    Some class object. 
417      *    Either <code>target == null</code> 
418      *    or <code>target instanceof aClass</code>. 
419      * @param target 
420      *    the object for which a field is to be accessed. 
421      *    For static fields, this <em>must</em> be <code>null</code>; 
422      *    whereas for memeber fields 
423      *    this has to be the corresponding instance. 
424      * @param fieldName 
425      *     the name of the field. 
426      * @return 
427      *    If the value of the specified field is an Object, 
428      *    this object is returned directly; 
429      *    otherwise the value of the field is wrapped 
430      *    in an object of the appropriate class. 
431      *    E.g. <code>new Integer(5)</code> is returned 
432      *    instead of the <code>int</code>-value <code>5</code>. 
433      * @throws NoSuchFieldException
434      *    if the specified class 
435      *    does not contain a field with the given name, 
436      *    e.g. because <code>fieldName == null</code>. 
437      * @throws IllegalArgumentException
438      *    <ul>
439      *    <li>
440      *    if the <code>null</code>-class is specified 
441      *    <li>
442      *    if the target is <code>null</code> 
443      *    whereas the specified field is a member field. 
444      *    <li>
445      *    if the target is not <code>null</code> 
446      *    whereas the specified field is static. 
447      *    </ul>
448      * @see #setField(Class, Object, String, Object)
449      */
450     public static Object getField(Class<?> aClass,
451 				  Object target,
452 				  String fieldName) 
453 	throws NoSuchFieldException {
454 
455 	Field aField = getFieldObj(aClass, fieldName, target == null);
456 
457 	try {
458 	    return aField.get(target);
459 	} catch (IllegalAccessException e) {
460 	    throw new IllegalStateException// NOPMD
461 		("Field '" + fieldName + STR_IN_CLS + 
462 		 (aClass == null ? target.getClass() : aClass).getName() + 
463 		 "is not accessible although it should. ");
464 	}
465     }
466 
467     /*----------------------------------------------------------------------*
468      * setField methods                                                     *
469      *----------------------------------------------------------------------*/
470 
471     /**
472      * If the type of the specified field extends <code>Object</code>, 
473      * invoking this method acts like <code>target.fieldName = value</code>; 
474      * otherwise the argument <code>value</code> is unwrapped first. 
475      * Note that there is no way to assign a value 
476      * to a field which is declared <code>final</code>. 
477      *
478      * @param target 
479      *    the object for which a field is to be accessed. 
480      * @param fieldName 
481      *     the name of the field. 
482      * @param value
483      *    If the type of the specified field extends <code>Object</code>, 
484      *    the type of <code>value</code> must be a supertype; 
485      *    otherwise it must be the corresponding wrapper. 
486      *    E.g. the field declared by <code>int intField;</code> 
487      *    is set by <code>setField(target, "intField", new Integer(5))</code> 
488      *    instead of <code>setField(target, "intField", 5)</code>. 
489      * @throws NoSuchFieldException
490      *    if the specified class 
491      *    does not contain a field with the given name. 
492      * @throws IllegalArgumentException
493      *    if the target is <code>null</code> 
494      *    or if the specified field is static 
495      *    or if the specified field is declared <code>final</code>. 
496      * @see #getField(Object, String)
497      */
498     public static void setField(Object target,
499 				String fieldName,
500 				Object value) 
501 	throws NoSuchFieldException {
502 
503 	if (target == null) {
504 	    throw new IllegalArgumentException
505 		("Specified null-target. ");
506 	}
507 	setField(target.getClass(), target, fieldName, value);
508     }
509 
510     /**
511      * If the type of the specified field extends <code>Object</code>, 
512      * invoking this method acts like <code>aClass.fieldName = value</code>; 
513      * otherwise the argument <code>value</code> is unwrapped first. 
514      * Note that there is no way to assign a value 
515      * to a field which is declared <code>final</code>. 
516      *
517      * @param aClass 
518      *    the class for which a static field is to be accessed. 
519      *    Typically one will use the expression 
520      *    <code>&lt;classname&gt;.class</code> 
521      *    to determine the class-object. 
522      * @param fieldName 
523      *     the name of the field. 
524      * @param value
525      *    If the type of the specified field extends <code>Object</code>, 
526      *    the type of <code>value</code> must be a supertype; 
527      *    otherwise it must be the corresponding wrapper. 
528      *    E.g. the field declared by <code>static int intField;</code> 
529      *    is set by <code>setField(aClass, "intField", new Integer(5))</code> 
530      *    instead of <code>setField(aClass, "intField", 5)</code>. 
531      * @throws NoSuchFieldException
532      *    if the specified class 
533      *    does not contain a field with the given name. 
534      * @throws IllegalArgumentException
535      *    if <code>aClass == null</code> 
536      *    or if the specified field is not static 
537      *    or if the specified field is declared <code>final</code>. 
538      * @see #getField(Class, String)
539      */
540     public static void setField(Class<?> aClass,
541 				String fieldName,
542 				Object value) 
543 	throws NoSuchFieldException {
544 
545 	setField(aClass, null, fieldName, value);
546     }
547 
548     /**
549      * If the type of the specified field extends <code>Object</code>, 
550      * invoking this method acts like <code>target.field = value</code>; 
551      * otherwise the argument <code>value</code> is unwrapped first. 
552      * Note that there is no way to assign a value 
553      * to a field which is declared <code>final</code>. 
554      *
555      * @param aClass 
556      *    Some class object. 
557      *    Either <code>target == null</code> 
558      *    or <code>target instanceof aClass</code>. 
559      * @param target 
560      *    the object for which a field is to be accessed. 
561      * @param fieldName 
562      *     the name of the field. 
563      * @param value
564      *    If the type of the specified field extends <code>Object</code>, 
565      *    the type of <code>value</code> must be the same; 
566      *    otherwise it must be the corresponding wrapper. 
567      * @throws NoSuchFieldException
568      *    if the specified class 
569      *    does not contain a field with the given name. 
570      * @throws IllegalArgumentException
571      *    <ul>
572      *    <li>
573      *    if the <code>null</code>-class is specified 
574      *    <li>
575      *    if the target is <code>null</code> 
576      *    whereas the specified field is a member field. 
577      *    <li>
578      *    if the target is not <code>null</code> 
579      *    whereas the specified field is static. 
580      *    <li>
581      *    if the specified field is declared <code>final</code>. 
582      *    <li>
583      *    if the specified field is primitive 
584      *    but a <code>null</code>-value is tried to be assigned. 
585      *    </ul>
586      * @see #getField(Class, Object, String)
587      */
588     public static void setField(Class<?> aClass,
589 				Object target,
590 				String fieldName,
591 				Object value) 
592 	throws NoSuchFieldException {
593 
594 	Field aField = getFieldObj(aClass, fieldName, target == null);
595 
596 	if (aField.getType().isPrimitive() && value == null) {
597 	    throw new IllegalArgumentException
598 		("Tried to assign null-value to field '" + fieldName + 
599 		 STR_IN_CLS + 
600 		 (aClass == null ? target.getClass() : aClass).getName() + 
601 		 "' although its type '" + aField.getType() + 
602 		 "' is primitive. ");
603 	}
604 
605 	try {
606 	    aField.set(target, value);
607 	} catch (IllegalAccessException e) {
608 	    if (aClass == null) {
609 		aClass = target.getClass();
610 	    }
611 	    String clsName = aClass.getName();
612 	    if (Modifier.isFinal(aField.getModifiers())) {
613 		throw new IllegalArgumentException// NOPMD
614 		    ("Field '" + fieldName + STR_IN_CLS + clsName + 
615 		     "' is declared final and is hence not accessible. ");
616 	    }
617 	    throw new IllegalStateException// NOPMD
618 		("Field '" + fieldName + STR_IN_CLS + clsName + 
619 		 "' is not accessible although it should. ");
620 	}
621     }
622 
623 
624     /*----------------------------------------------------------------------*
625      * invoke methods with implicitly specified parameter types             *
626      *----------------------------------------------------------------------*/
627 
628     /**
629      * For invoking static methods. 
630      *
631      * @param aClass 
632      *    The class of the static method to be invoked. 
633      *    The method is looked up recursively 
634      *    in the superclasses of <code>aClass</code>. 
635      *    Typically one will use the expression 
636      *    <code>&lt;classname&gt;.class</code> 
637      *    to determine the class-object. 
638      * @param methodName 
639      *    the short name of a static method. 
640      *    Short means without package or class. 
641      * @param parameters 
642      *    the list of parameters used when invoking <code>methodName</code>. 
643      *    Note that parameters of elementary types 
644      *    have to be wrapped in an object 
645      *    (e.g. write <code>new Integer(8)</code> 
646      *    instead of just <code>8</code>). 
647      * @return
648      *    <ul>
649      *    <li>
650      *    If the return type of the specified method 
651      *    is <code>Object</code> or a subclass, 
652      *    the return value is returned directly; 
653      *    <li>
654      *    if it is a primitive type, it is wrapped 
655      *    in an object of the appropriate class. 
656      *    E.g. <code>new Integer(5)</code> is returned 
657      *    instead of the <code>int</code>-value <code>5</code>. 
658      *    <li>
659      *    If the return type is void, 
660      *    i.e. <code>java.lang.Void.TYPE</code>, 
661      *    <code>null</code> is returned. 
662      *    </ul>
663      * @throws IllegalArgumentException
664      *    <ul>
665      *    <li>
666      *    if <code>aClass == null</code>. 
667      *    <li>
668      *    if the specified method does not exist or is not unique. 
669      *    </ul>
670      * @throws InvocationTargetException 
671      *   to wrap an exception thrown by the method invoked. 
672      *   Unwrap it using {@link Throwable#getCause}. 
673      * @see #invoke(Class, Object, String, Object...)
674      */
675     public static Object invokeStatic(Class<?> aClass,
676 				      String methodName,
677 				      Object... parameters) 
678 	throws InvocationTargetException {
679 
680 	return invoke(aClass, null, methodName, parameters);
681     }
682 
683     /**
684      * For invoking member methods. 
685      *
686      * @param target 
687      *    the target on which the specified member method is to be applied. 
688      * @param methodName 
689      *    the short name of a static method. 
690      *    Short means without package or class. 
691      * @param parameters 
692      *    the list of parameters used when invoking <code>methodName</code>. 
693      *    Note that parameters of elementary types 
694      *    have to be wrapped in an object 
695      *    (e.g. write <code>new Integer(8)</code> 
696      *    instead of just <code>8</code>). 
697      * @return
698      *    <ul>
699      *    <li>
700      *    If the return type of the specified method 
701      *    is <code>Object</code> or a subclass, 
702      *    the return value is returned directly; 
703      *    <li>
704      *    if it is a primitive type, it is wrapped 
705      *    in an object of the appropriate class. 
706      *    E.g. <code>new Integer(5)</code> is returned 
707      *    instead of the <code>int</code>-value <code>5</code>. 
708      *    <li>
709      *    If the return type is void, 
710      *    i.e. <code>java.lang.Void.TYPE</code>, 
711      *    <code>null</code> is returned. 
712      *    </ul>
713      * @throws IllegalArgumentException
714      *    <ul>
715      *    <li>
716      *    if <code>target == null</code>. 
717      *    <li>
718      *    if the specified method does not exist or is not unique. 
719      *    </ul>
720      * @throws InvocationTargetException 
721      *   to wrap an exception thrown by the method invoked. 
722      *   Unwrap it using {@link Throwable#getCause}. 
723      * @see #invoke(Class, Object, String, Object...)
724      */
725     public static Object invoke(Object target,
726 				String methodName,
727 				Object... parameters) 
728 	throws InvocationTargetException {
729 
730 	return invoke(target.getClass(), target, methodName, parameters);
731     }
732 
733     /**
734      * Invokes the specified method with the given parameters 
735      * and returns the value (which may be void of course. ) 
736      * <p>
737      * CAUTION: This may cause an exception although the runtime system 
738      * finds out which method is ment. 
739      * This is the case if for example 
740      * methods <code>exa(int)</code> and <code>exa(Integer)</code> 
741      * are present: 
742      * both are invoked with 
743      * <code>invoke(cls, target, "exa", new Integer(0))}</code>. 
744      * In this case 
745      * use {@link #invoke(Class, Object, String, Class[], Object[])} instead. 
746      * 
747      * @param aClass 
748      *    The class of the method to be invoked. 
749      *    The method is looked up recursively 
750      *    in the superclasses of <code>aClass</code>. 
751      *    Typically one will use the expression 
752      *    <code>&lt;classname&gt;.class</code> 
753      *    to determine the class-object. 
754      * @param target 
755      *    the target to which the specified method is to be applied. 
756      *    the target <em>must</em> be <code>null</code>
757      *    if and only if the method specified is static. 
758      * @param methodName 
759      *    the short name of a method. 
760      *    Short means without package or class. 
761      * @param parameters 
762      *    the list of parameters used when invoking <code>methodName</code>. 
763      *    Note that parameters of elementary types 
764      *    have to be wrapped in an object 
765      *    (e.g. write <code>new Integer(8)</code> 
766      *    instead of just <code>8</code>). 
767      * @return
768      *    <ul>
769      *    <li>
770      *    If the return type of the specified method 
771      *    is <code>Object</code> or a subclass, 
772      *    the return value is returned directly; 
773      *    <li>
774      *    if it is a primitive type, it is wrapped 
775      *    in an object of the appropriate class. 
776      *    E.g. <code>new Integer(5)</code> is returned 
777      *    instead of the <code>int</code>-value <code>5</code>. 
778      *    <li>
779      *    If the return type is void, 
780      *    i.e. <code>java.lang.Void.TYPE</code>, 
781      *    <code>null</code> is returned. 
782      *    </ul>
783      * @throws InvocationTargetException 
784      *   to wrap an exception thrown by the method invoked. 
785      *   Unwrap it using {@link Throwable#getCause}. 
786      * @throws IllegalArgumentException
787      *    <ul>
788      *    <li>
789      *    if <code>aClass == null</code>. 
790      *    <li>
791      *    if the specified method is static but <code>target != null</code>. 
792      *    <li>
793      *    if the specified method is a member method 
794      *    but <code>target == null</code>. 
795      *    <li>
796      *    if the specified method does not exist or is not unique. 
797      *    </ul>
798      */
799     public static Object invoke(Class<?> aClass,
800 				Object target,
801 				String methodName,
802 				Object... parameters) 
803 	throws InvocationTargetException {
804 	
805 	if (aClass == null) {
806 	    throw new IllegalArgumentException(STR_SPEC_NULL_CLS);
807 	}
808 
809 	Method[] cands;
810 	Class<?> candClass = aClass;
811 	Method toBeInvoked;
812  
813 	// Find out the methods matching the signature 
814 	// and collect them in "cands". 
815 	do {
816 	    cands = candClass.getDeclaredMethods();
817 
818 	    toBeInvoked = getMethod(aClass,
819 				    methodName,
820 				    cands,
821 				    parameters);
822 
823 	    if (toBeInvoked != null) {
824 		return invoke(toBeInvoked, target, parameters);
825 	    }
826 	    // prepare search in superclass. 
827 	    candClass = candClass.getSuperclass();
828 	} while (candClass != null);
829 	// Here, the desired method is not found. 
830 
831 	throw new IllegalArgumentException
832 	    ("Method " + aClass.getName() + "." + methodName + 
833 	     paramsToString(getParamCls(parameters)) + STR_DNE);
834     }
835 
836     /**
837      * If more than one method with the same parameter types 
838      * is declared in a class, 
839      * and one of these methods has a return type 
840      * that is more specific than any of the others, 
841      * that method is returned; 
842      * otherwise one of the methods is chosen arbitrarily. 
843      * 
844      * @param aClass 
845      *    The class of the method to be invoked. 
846      *    The method is looked up recursively 
847      *    in the superclasses of <code>aClass</code>. 
848      *    Typically one will use the expression 
849      *    <code>&lt;classname&gt;.class</code> 
850      *    to determine the class-object. 
851      * @param target 
852      *    the target to which the specified method is to be applied. 
853      *    If the method specified is static, the target is ignored. 
854      *    Convention: should be <code>null</code> in this case. 
855      * @param methodName 
856      *    the short name of a method. 
857      *    Short means without package or class. 
858      * @param paramCls 
859      *    the types specifying the parameter list of the desired method. 
860      *    Typically one will use the expression 
861      *    <code>&lt;classname&gt;.class</code> 
862      *    to denote a class, even a primitive one. 
863      *    For primitive types, the alternatives 
864      *            java.lang.Boolean.TYPE 
865      *            java.lang.Character.TYPE 
866      *            java.lang.Byte.TYPE 
867      *            java.lang.Short.TYPE 
868      *            java.lang.Integer.TYPE 
869      *            java.lang.Long.TYPE 
870      *            java.lang.Float.TYPE 
871      *            java.lang.Double.TYPE 
872      *           (java.lang.Void.TYPE) 
873      *    are available. 
874      *    For hidden inner classes, e.g. <code>private</code> ones, 
875      *    {@link #getInnerClass(Class, String[])} and 
876      *    {@link #getInnerClass(Class, String)} 
877      *    may be used. 
878      *    If an object <code>i</code> of a desired class is present 
879      *    and if the class of is <code>i</code> not primitive, 
880      *    <code>i.getClass()</code> returns the desired class object as well. 
881      * @param parameters 
882      *    the list of parameters used when invoking <code>methodName</code>. 
883      *    Note that parameters of elementary types 
884      *    have to be wrapped in an object 
885      *    (e.g. write <code>new Integer(8)</code> 
886      *    instead of just <code>8</code>). 
887      * @return
888      *    <ul>
889      *    <li>
890      *    If the return type of the specified method 
891      *    is <code>Object</code> or a subclass, 
892      *    the return value is returned directly; 
893      *    <li>
894      *    if it is a primitive type, it is wrapped 
895      *    in an object of the appropriate class. 
896      *    E.g. <code>new Integer(5)</code> is returned 
897      *    instead of the <code>int</code>-value <code>5</code>. 
898      *    <li>
899      *    If the return type is void, 
900      *    i.e. <code>java.lang.Void.TYPE</code>, 
901      *    <code>null</code> is returned. 
902      *    </ul>
903      * @throws IllegalArgumentException 
904      *    if the specified method does not exist. 
905      * @throws InvocationTargetException 
906      *   to wrap an exception thrown by the method invoked. 
907      *   Unwrap it using {@link Throwable#getCause}. 
908      * @see #invoke(Class, Object, String, Class[], Object[])
909      */
910     public static Object invoke(Class<?> aClass,
911 				Object target,
912 				String methodName,
913 				Class<?>[] paramCls,
914 				Object[] parameters) 
915 	throws InvocationTargetException {
916 
917 	if (aClass == null) {
918 	    throw new IllegalArgumentException(STR_SPEC_NULL_CLS);
919 	}
920 	Method toBeInvoked = getToBeInvoked(aClass, methodName, paramCls);
921 	if (toBeInvoked != null) {
922 	    return invoke(toBeInvoked, target, parameters);
923 	}
924 	// Here, the desired method is not found. 
925 
926 	throw new IllegalArgumentException
927 	    ("Method " + aClass.getName() + "." + methodName + 
928 	     paramsToString(getParamCls(parameters)) + STR_DNE);
929     }
930 
931     /**
932      * Returns the specified method if it exists; 
933      * otherwise <code>null</code>. 
934      * Note that it is searched in the superclasses as well. 
935      *
936      * @param aClass 
937      *    the <code>Class</code> to start searching the method. 
938      *    Typically one will use the expression 
939      *    <code>&lt;classname&gt;.class</code> 
940      *    to determine the class-object. 
941      * @param methodName 
942      *    the name of the method to be returned. 
943      * @param paramCls 
944      *    the types specifying the parameter list of the desired method. 
945      * @return 
946      *    the method with the specified name and parameter list. 
947      *    The search is started in <code>candClass</code> 
948      *    and descends recursively until a method is found. 
949      *    If no method is found, <code>null</code> is returned. 
950      */
951     static Method getToBeInvoked(Class<?> aClass,
952 				 String methodName,
953 				 Class<?>... paramCls) {
954 
955 	Method toBeInvoked;
956 	for (Class<?> candClass = aClass; 
957 	     candClass != null;
958 	     candClass = candClass.getSuperclass()) {
959 	    try {
960 		toBeInvoked = candClass.getDeclaredMethod(methodName, paramCls);
961 	    } catch (NoSuchMethodException e) {
962 		// method is not found: look it up in subclass. 
963 		continue;
964 	    }
965 	    if (Modifier.isAbstract(toBeInvoked.getModifiers())) {
966 		return null;
967 	    }
968 	    toBeInvoked.setAccessible(true);
969 	    return toBeInvoked; // NOPMD 
970 	}
971 	// Here, the desired method is not found. 
972 
973 	return null;
974     }
975 
976 
977     /*----------------------------------------------------------------------*
978      * create methods                                                       *
979      *----------------------------------------------------------------------*/
980 
981     /**
982      * Returns an object created by the specified constructor. 
983      * Note that this method is not applicable to 
984      * interfaces, primitive types, array classes, or void. 
985      * In the context of this package, these restrictions are not severe. 
986      *
987      * @param aClass 
988      *    the class of the instance to be created. 
989      *    Typically one will use the expression 
990      *    <code>&lt;classname&gt;.class</code> 
991      *    to determine the class-object. 
992      * @param parameters 
993      *    the list of parameters of the specified constructor. 
994      *    Note that parameters of elementary types 
995      *    have to be wrapped in an object 
996      *    (e.g. write <code>new Integer(8)</code> 
997      *    instead of just <code>8</code>). 
998      *    <p>
999      *    Note also that for static inner classes, 
1000      *    formally the surrounding instance is prefixed as a parameter. 
1001      *    ****** i think this does not apply to methods, 
1002      *    but actually i did not try yet. 
1003      * @return 
1004      *    an <code>Object</code> created by the specified constructor. 
1005      * @throws InstantiationException 
1006      *    if the instantiation with the specified constructor failed. 
1007      * @throws IllegalArgumentException 
1008      *    if the specified constructor does not exist or is not unique. 
1009      * @throws InvocationTargetException 
1010      *   to wrap an exception thrown by the constructor invoked. 
1011      *   Unwrap it using {@link Throwable#getCause}. 
1012      */
1013     public static <T> T create(Class<T> aClass, 
1014 			       Object... parameters) 
1015 	throws InstantiationException, InvocationTargetException {
1016 	
1017 	
1018 	Constructor<T> toBeInvoked = getConstructor(aClass, parameters);
1019 	// toBeInvoked may also be the default constructor, 
1020 	// although this is not EXPLICITLY declared, of course. 
1021 
1022 	if (toBeInvoked == null) {
1023 	    throw new IllegalArgumentException
1024 		("Constructor " + aClass.getName() + 
1025 		 paramsToString(getParamCls(parameters)) + 
1026 		 STR_DNE);
1027 	}
1028 	return create(toBeInvoked, parameters);
1029     }
1030 
1031     /*
1032      * Returns an instance of the class given by <code>aClass</code> 
1033      * generated by the default constructor. 
1034      *
1035      * @param aClass 
1036      *    a <code>Class</code> object. 
1037      *    Typically one will use the expression 
1038      *    <code>&lt;classname&gt;.class</code> 
1039      *    to determine the class-object. 
1040      * @return 
1041      *    an <code>Object</code> created by the default constructor 
1042      *    of the specified class. 
1043      * @exception InstantiationException 
1044      *    if an error occurs in the default constructor. 
1045      */
1046     /*
1047     private static Object createDefault(Class aClass) 
1048     throws InstantiationException {
1049 	try {
1050 	    return aClass.newInstance();
1051 	} catch (IllegalAccessException e) {
1052 	    throw new IllegalStateException
1053 		("Found unexpected exception " + e + 
1054 		 " while trying to invoke default constructor " + 
1055 		 "which is not declared. ");
1056 	}
1057     }
1058     */
1059 
1060     /**
1061      * Returns an object created by the specified constructor. 
1062      * Note that this method is not applicable to 
1063      * interfaces, primitive types, array classes, or void. 
1064      * In the context of this package, these restrictions are not severe. 
1065      *
1066      * @param aClass 
1067      *    the class of the instance to be created 
1068      *    Typically one will use the expression 
1069      *    <code>&lt;classname&gt;.class</code> 
1070      *    to determine the class-object. 
1071      * @param paramCls 
1072      *    the types specifying the parameter list of the desired method. 
1073      *    Typically one will use the expression 
1074      *    <code>&lt;classname&gt;.class</code> 
1075      *    to denote a class, even a primitive one. 
1076      *    For primitive types, the alternatives 
1077      *            java.lang.Boolean.TYPE 
1078      *            java.lang.Character.TYPE 
1079      *            java.lang.Byte.TYPE 
1080      *            java.lang.Short.TYPE 
1081      *            java.lang.Integer.TYPE 
1082      *            java.lang.Long.TYPE 
1083      *            java.lang.Float.TYPE 
1084      *            java.lang.Double.TYPE 
1085      *           (java.lang.Void.TYPE) 
1086      *    are available. 
1087      *    For hidden inner classes, e.g. <code>private</code> ones, 
1088      *    {@link #getInnerClass(Class, String[])} and 
1089      *    {@link #getInnerClass(Class, String)} 
1090      *    may be used. 
1091      *    If an object <code>i</code> of a desired class is present 
1092      *    and if the class of is <code>i</code> not primitive, 
1093      *    <code>i.getClass()</code> returns the desired class object as well. 
1094      *    <p>
1095      *    Note also that for static inner classes, 
1096      *    formally the surrounding class is prefixed as a parameter. 
1097      *    ****** i think this does not apply to methods, 
1098      *    but actually i did not try yet. 
1099      * @param parameters 
1100      *    the list of parameters of the specified constructor. 
1101      *    Note that parameters of elementary types 
1102      *    have to be wrapped in an object 
1103      *    (e.g. write <code>new Integer(8)</code> 
1104      *    instead of just <code>8</code>). 
1105      *    <p>
1106      *    Note also that for static inner classes, 
1107      *    formally the surrounding instance is prefixed as a parameter. 
1108      *    ****** i think this does not apply to methods, 
1109      *    but actually i did not try yet. 
1110      * @return 
1111      *    an <code>Object</code> created by the specified constructor. 
1112      * @throws InstantiationException 
1113      *    if the instantiation with the specified constructor failed. 
1114      * @throws NoSuchMethodException 
1115      *    if the specified constructor does not exist. 
1116      * @throws InvocationTargetException 
1117      *   to wrap an exception thrown by the constructor invoked. 
1118      *   Unwrap it using {@link Throwable#getCause}. 
1119      */
1120     public static <T> T create(Class<T> aClass,
1121 			       Class<?>[] paramCls,
1122 			       Object... parameters) 
1123 	throws NoSuchMethodException, 
1124 	InstantiationException, 
1125 	InvocationTargetException {
1126 
1127 	// includes the default constructor?!? -- not specified! 
1128 	Constructor<T> toBeInvoked = aClass
1129 	    .getDeclaredConstructor(paramCls);
1130 	if (toBeInvoked == null) {
1131 	    throw new IllegalArgumentException
1132 		("Constructor " + aClass.getName() + 
1133 		 paramsToString(paramCls) + STR_DNE);
1134 	}
1135 	toBeInvoked.setAccessible(true);
1136 	return create(toBeInvoked, parameters);
1137     }
1138 
1139     /**
1140      * Invoke the specified constructor with the given arguments. 
1141      *
1142      * @param toBeInvoked 
1143      *    some <code>Constructor</code>. 
1144      * @param parameters
1145      *    parameters fitting the given <code>Constructor</code>. 
1146      * @throws InstantiationException 
1147      *    if the instantiation with the specified constructor failed. 
1148      * @throws InvocationTargetException 
1149      *   to wrap an exception thrown by the constructor invoked. 
1150      *   Unwrap it using {@link Throwable#getCause}. 
1151      */
1152     private static <T> T create(Constructor<T> toBeInvoked,
1153 				Object... parameters) 
1154 	throws InstantiationException, InvocationTargetException {
1155 
1156 	try {
1157 	    return toBeInvoked.newInstance(parameters);
1158 	} catch (IllegalAccessException ie) {
1159 	    throw new IllegalStateException// NOPMD
1160 		("Constructor should be accessible; still is not. "); 
1161 	}
1162     }
1163 
1164     /**
1165      * Returns whether the given method 
1166      * matches the name and the parameter list. 
1167      *
1168      * @param cand 
1169      *    either a <code>Constructor</code> or a <code>Method</code>. 
1170      * @param methodName  
1171      *    the required name of a <code>Method</code>. 
1172      *    If <code>cand</code> is a constructor, this field is ignored; 
1173      *    if it is a method the name of which does not match, 
1174      *    <code>null</code> is returned. 
1175      * @param parameters 
1176      *    the list of parameters. 
1177      * @return 
1178      *    <code>true</code> if and only if 
1179      *    all of the following conditions are satisfied: 
1180      *    <ul>
1181      *    <li>
1182      *    <code>cand</code> is either a non-abstract method 
1183      *    named <code>methodName</code>. 
1184      *    <li>
1185      *    the parameter list of <code>cand</code> 
1186      *    matches <code>parameters</code> 
1187      *    as specified for {@link #paramsMatch}. 
1188      *    </ul>
1189      * @throws IllegalStateException 
1190      *    if <code>cand</code> is neither a method nor a constructor. 
1191      */
1192     private static boolean methodMatches(Method cand,
1193 					 String methodName,
1194 					 Object... parameters) {
1195 	// Check name. 
1196 	if (!cand.getName().equals(methodName)) {
1197 	    return false;
1198 	}
1199 	// Here, cand has the right name. 
1200 
1201 	// Check not abstract. 
1202 	if (Modifier.isAbstract(cand.getModifiers())) {
1203 	    return false;
1204 	}
1205 	// Here, cand is not abstract. 
1206 
1207 	// Here, paramTypes contains the parameter types of cand. 
1208 
1209 	return paramsMatch(cand.getParameterTypes(), parameters);
1210     }
1211 
1212     /**
1213      * Returns whether the given constructor matches the parameter list. 
1214      *
1215      * @param cand 
1216      *    either a <code>Constructor</code> or a <code>Method</code>. 
1217      * @param parameters 
1218      *    the list of parameters. 
1219      * @return a 
1220      *    <code>true</code> if and only if 
1221      *    the parameter list of <code>cand</code> 
1222      *    matches <code>parameters</code> 
1223      *    as specified for {@link #paramsMatch}. 
1224      * @throws IllegalStateException 
1225      *    if <code>cand</code> is neither a method nor a constructor. 
1226      */
1227     private static <T> boolean constructorMatches(Constructor<T> cand,
1228 						  Object... parameters) {
1229 	return paramsMatch(cand.getParameterTypes(), parameters);
1230     }
1231 
1232     /**
1233      * Returns whether the given the parameter list matches the classes. 
1234      *
1235      * @param paramTypes 
1236      *    the list of classes of parameters. 
1237      * @param parameters 
1238      *    the list of parameters. 
1239      * @return a 
1240      *    <code>true</code> if and only if 
1241      *    the parameter list of <code>cand</code> 
1242      *    matches <code>parameters</code> 
1243      *    up to equivalence of primitive types and their wrappers. 
1244      *    This includes that the two arrays have the same length. 
1245      * @throws IllegalStateException 
1246      *    if <code>cand</code> is neither a method nor a constructor. 
1247      */
1248     private static boolean paramsMatch(Class<?>[] paramTypes,
1249 				       Object... parameters) {
1250 	if (paramTypes.length != parameters.length) {
1251 	    return false;
1252 	}
1253 	// Here, the name and the number of parameters match. 
1254 
1255 	for (int j = 0; j < parameters.length; j++) {
1256 	    if (!BasicTypesCompatibilityChecker
1257 		.areCompatible(paramTypes[j], parameters[j])) {
1258 		return false;
1259 	    }
1260 	}
1261 	// Here, the complete signature matches 
1262 	// (except for the return type). 
1263 	return true;
1264     }
1265 
1266     /**
1267      * Returns the specified method 
1268      * if <code>cands</code> offers exactly one possibility. 
1269      *
1270      * @param aClass 
1271      *    the <code>Class</code> 
1272      *    in which to search a <code>Method</code>. 
1273      *    For error/exception messages only. 
1274      * @param methodName 
1275      *    the name of the desired <code>Method</code>. 
1276      * @param cands 
1277      *    an array of <code>Method</code>s 
1278      *    the return value of this method is choosen from. 
1279      * @param parameters 
1280      *    the list of parameters. 
1281      * @return 
1282      *    a <code>Method</code>; possibly <code>null</code> 
1283      *    if the specified <code>Method</code> 
1284      *    does not exist in the specified class. 
1285      * @throws IllegalArgumentException 
1286      *    if the specified constructor or method is not unique. 
1287      */
1288     private static Method getMethod(Class<?> aClass,
1289 				    String methodName,
1290 				    Method[] cands,
1291 				    Object... parameters) {
1292 
1293 	// "null" means that no method or constructor has been found so far. 
1294 	Method result = null;
1295 
1296 	for (int i = 0; i < cands.length; i++) {
1297 	    if (!methodMatches(cands[i], methodName, parameters)) {
1298 		continue;
1299 	    }
1300 
1301 	    if (result != null) {
1302 		// Found more than one method/constructor. 
1303 		throw new IllegalArgumentException
1304 		    ("Method " + aClass.getName() + "." + methodName + 
1305 		     paramsToString(getParamCls(parameters)) + 
1306 		     " is not unique: cannot distinguish " + result + 
1307 		     " from " + cands[i] + ". ");
1308 	    }
1309 	    // cands[i] is the first method that matches. 
1310 	    result = cands[i];
1311 	} // for all cands 
1312 
1313 	if (result != null) {
1314 	    result.setAccessible(true);
1315 	}
1316 	return result;
1317     }
1318 
1319     /**
1320      * Returns the specified constructor 
1321      * if <code>aClas</code> offers exactly one possibility 
1322      * with the given parameters. 
1323      *
1324      * @param aClass 
1325      *    the <code>Class</code> 
1326      *    in which to search a <code>Constructor</code>. 
1327      *    For error/exception messages only. 
1328      * @param parameters 
1329      *    the list of parameters. 
1330      * @return 
1331      *    a <code>Constructor</code> or <code>null</code> 
1332      *    if the specified constructor 
1333      *    does not exist in the specified class. 
1334      * @throws IllegalArgumentException 
1335      *    if the specified constructor or method is not unique. 
1336      */
1337     private static <T> Constructor<T> getConstructor(Class<T> aClass,
1338 						     Object... parameters) {
1339 
1340 	Constructor<?>[] cands = //(Constructor<T>[])
1341 	    aClass.getDeclaredConstructors();
1342 
1343 	// "null" means that no method or constructor has been found so far. 
1344 	Constructor<T> result = null;
1345 
1346 	for (int i = 0; i < cands.length; i++) {
1347 	    if (!constructorMatches(cands[i], parameters)) {
1348 		continue;
1349 	    }
1350 
1351 	    if (result != null) {
1352 		// Found more than one method/constructor. 
1353 		throw new IllegalArgumentException
1354 		    ("Constructor " + aClass.getName() + 
1355 		     paramsToString(getParamCls(parameters)) + 
1356 		     " is not unique: cannot distinguish " + result + 
1357 		     " from " + cands[i] + ". ");
1358 	    }
1359 	    // cands[i] is the first constructor that matches. 
1360 
1361 	    try {
1362 		// one would just write result = (Constructor<T>)cands[i];
1363 		result = aClass
1364 		    .getDeclaredConstructor(cands[i].getParameterTypes());
1365 		// not assert result == cands[i]
1366 		assert result.equals(cands[i]); 
1367 		// **** the cast is a weakness in the jdk5 (reported)
1368 		// because cands is an array and these cannot be generified 
1369 		// **** in jdk6 hardly any improvement (to be rep.) 
1370 		// possible solution is: use a List but with other disadvantages
1371 	    } catch (NoSuchMethodException e) {
1372 		throw new IllegalStateException("****"); // NOPMD
1373 	    }
1374 
1375 	} // for all cands 
1376 
1377 	if (result != null) {
1378 	    result.setAccessible(true);
1379 	}
1380 	return result;
1381     }
1382 
1383     /*----------------------------------------------------------------------*
1384      * getInnerClass methods                                                *
1385      *----------------------------------------------------------------------*/
1386 
1387 
1388     /**
1389      * Returns the inner class of <code>enclosingCls</code> 
1390      * with the specified name <code>innerClsName</code>. 
1391      * By inner classes we mean both static inner classes and member classes. 
1392      * Also inherited classes are included. 
1393      *
1394      * @param enclosingCls 
1395      *    a <code>Class</code> object which may also be an inner class, 
1396      *    static or not. 
1397      * @param pathToInner
1398      *    a short path of a class enclosed by <code>enclosingCls</code>. 
1399      *    If the name of the enclosing class is <tt>enclosing</tt> 
1400      *    then the name of the inner class has the form 
1401      *    <tt>enclosing$shortName</tt>. 
1402      *    Here, "$" is as specified in {@link #INNER_SEPARATOR}. 
1403      *    This remains also true for nested inner classes. 
1404      *    In this case, <tt>shortName</tt> itself has the form 
1405      *    <tt>cls1$...$clsN</tt>. 
1406      *    The the corresponding short path is 
1407      *    <code>new String[] {cls1, ..., clsN}</code>. 
1408      *    For paths with length <code>1</code> 
1409      *    one may use {@link #getInnerClass(Class, String)} instead. 
1410      * @return 
1411      *    the <code>Class</code> object represented by the parameters. 
1412      * @throws IllegalArgumentException
1413      *    if either of the parameters is <code>null</code>. 
1414      * @throws IllegalArgumentException
1415      *    if the specified class does not exist. 
1416      * @see #getInnerClass(Class, String)
1417      */
1418     public static Class<?> getInnerClass(Class<?> enclosingCls,
1419 					 String[] pathToInner) {
1420 	Class<?> result = enclosingCls;
1421 	for (int i = 0; i < pathToInner.length; i++) {
1422 	    result = getInnerClass(result, pathToInner[i]);
1423 	}
1424 	return result;
1425     }
1426 
1427     /**
1428      * Returns the inner class of <code>enclosingCls</code> 
1429      * with the specified name <code>innerClsName</code>. 
1430      * By inner classes we mean both static inner classes and member classes. 
1431      * Also inherited classes are included. 
1432      *
1433      * @param enclosingCls 
1434      *    a <code>Class</code> object which may also be an inner class, 
1435      *    static or not. 
1436      * @param innerClsName 
1437      *    a short name of a class enclosed by <code>enclosingCls</code>. 
1438      *    If the name of the enclosing class is <tt>enclosing</tt> 
1439      *    then the name of the inner class has the form 
1440      *    <tt>enclosing$shortName</tt>. 
1441      *    Here, "$" is as specified in {@link #INNER_SEPARATOR}. 
1442      *    This remains also true for nested inner classes. 
1443      *    In this case, <tt>shortName</tt> itself has the form 
1444      *    <tt>cls1$...$clsN</tt>. 
1445      *    <em>CAUTION</em> 
1446      *    In this case apply method {@link #getInnerClass(Class, String[])} 
1447      *    instead. 
1448      * @return 
1449      *    the <code>Class</code> object represented by the parameters. 
1450      * @throws IllegalArgumentException
1451      *    if either of the parameters is <code>null</code> or 
1452      *    if the specified class does not exist. 
1453      * @see #getInnerClass(Class, String[])
1454      */
1455     public static Class<?> getInnerClass(Class<?> enclosingCls,
1456 					 String innerClsName) {
1457 
1458 	if (enclosingCls == null) {
1459 	    throw new IllegalArgumentException(STR_SPEC_NULL_CLS);
1460 	}
1461 	if (innerClsName == null) {
1462 	    throw new IllegalArgumentException
1463 		("Specified null-class-name. ");
1464 	}
1465 
1466 	Class<?>[] cands;
1467 	Class<?> candCls = enclosingCls;
1468 	String candClsName;
1469 
1470 	do {
1471 	    // look for the specified inner class in candClass. 
1472 
1473 	    cands = candCls.getDeclaredClasses();
1474 	    candClsName = candCls.getName() + INNER_SEPARATOR;
1475 
1476 	    for (int i = 0; i < cands.length; i++) {
1477 		if (cands[i].getName().equals(candClsName + innerClsName)) {
1478 		    return cands[i];
1479 		}
1480 	    }
1481 	    // prepare search in superclass. 
1482 	    candCls = candCls.getSuperclass();
1483 	} while (candCls != null);
1484 	// Here, the specified inner class is not found. 
1485 
1486 	throw new IllegalArgumentException
1487 	    ("Class '" + enclosingCls.getName() + 
1488 	     "' has no inner class named '" + innerClsName + "'. ");
1489     }
1490 }
1491 
1492 
1493 
1494 // Accessor.java:157: warning: [rawtypes] found raw type: Class
1495 //     private static String paramsToString(Class... paramCls) {
1496 //                                          ^
1497 //   missing type arguments for generic class Class<T>
1498 //   where T is a type-variable:
1499 //     T extends Object declared in class Class
1500 // Accessor.java:910: warning: [rawtypes] found raw type: Class
1501 // 				Class[] paramCls,
1502 // 				^
1503 //   missing type arguments for generic class Class<T>
1504 //   where T is a type-variable:
1505 //     T extends Object declared in class Class
1506 // Accessor.java:1019: warning: [unchecked] unchecked cast
1507 // 			   (Constructor<T>[])aClass.getDeclaredConstructors(),
1508 // 			                                                   ^
1509 //   required: Constructor<T>[]
1510 //   found:    Constructor<?>[]
1511 //   where T is a type-variable:
1512 //     T extends Object declared in method <T>create(Class<T>,Object...)
1513 // Accessor.java:1123: warning: [rawtypes] found raw type: Class
1514 // 			       Class[] paramCls,
1515 // 			       ^
1516 //   missing type arguments for generic class Class<T>
1517 //   where T is a type-variable:
1518 //     T extends Object declared in class Class
1519 // Accessor.java:1250: warning: [rawtypes] found raw type: Class
1520 //     private static boolean paramsMatch(Class[] paramTypes,
1521 //                                        ^
1522 //   missing type arguments for generic class Class<T>
1523 //   where T is a type-variable:
1524 //     T extends Object declared in class Class
1525 // Accessor.java:1453: warning: [rawtypes] found raw type: Class
1526 // 	Class[] cands;
1527 // 	^
1528 //   missing type arguments for generic class Class<T>
1529 //   where T is a type-variable:
1530 //     T extends Object declared in class Class
1531 // 6 warnings
1532 
1533 // Compilation finished at Mon Oct 23 00:05:00