1// Copyright 2006 The Android Open Source Project
2
3import java.lang.reflect.*;
4import java.io.IOException;
5import java.util.Collections;
6import java.util.ArrayList;
7import java.util.List;
8import java.util.Map;
9
10/**
11 * Reflection test.
12 */
13public class Main {
14    private static boolean FULL_ACCESS_CHECKS = false;  // b/5861201
15    public Main() {}
16    public Main(ArrayList<Integer> stuff) {}
17
18    void printMethodInfo(Method meth) {
19        Class[] params, exceptions;
20        int i;
21
22        System.out.println("Method name is " + meth.getName());
23        System.out.println(" Declaring class is "
24            + meth.getDeclaringClass().getName());
25        params = meth.getParameterTypes();
26        for (i = 0; i < params.length; i++)
27            System.out.println(" Arg " + i + ": " + params[i].getName());
28        exceptions = meth.getExceptionTypes();
29        for (i = 0; i < exceptions.length; i++)
30            System.out.println(" Exc " + i + ": " + exceptions[i].getName());
31        System.out.println(" Return type is " + meth.getReturnType().getName());
32        System.out.println(" Access flags are 0x"
33            + Integer.toHexString(meth.getModifiers()));
34        //System.out.println(" GenericStr is " + meth.toGenericString());
35    }
36
37    void printFieldInfo(Field field) {
38        System.out.println("Field name is " + field.getName());
39        System.out.println(" Declaring class is "
40            + field.getDeclaringClass().getName());
41        System.out.println(" Field type is " + field.getType().getName());
42        System.out.println(" Access flags are 0x"
43            + Integer.toHexString(field.getModifiers()));
44    }
45
46    private void showStrings(Target instance)
47        throws NoSuchFieldException, IllegalAccessException {
48
49        Class target = Target.class;
50        String one, two, three, four;
51        Field field = null;
52
53        field = target.getField("string1");
54        one = (String) field.get(instance);
55
56        field = target.getField("string2");
57        two = (String) field.get(instance);
58
59        field = target.getField("string3");
60        three = (String) field.get(instance);
61
62        System.out.println("  ::: " + one + ":" + two + ":" + three);
63    }
64
65    public static void checkAccess() {
66        try {
67            Class target = otherpackage.Other.class;
68            Object instance = new otherpackage.Other();
69            Method meth;
70
71            meth = target.getMethod("publicMethod", (Class[]) null);
72            meth.invoke(instance);
73
74            try {
75                meth = target.getMethod("packageMethod", (Class[]) null);
76                System.err.println("succeeded on package-scope method");
77            } catch (NoSuchMethodException nsme) {
78                // good
79            }
80
81
82            instance = otherpackage.Other.getInnerClassInstance();
83            target = instance.getClass();
84            meth = target.getMethod("innerMethod", (Class[]) null);
85            try {
86                if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
87                meth.invoke(instance);
88                System.err.println("inner-method invoke unexpectedly worked");
89            } catch (IllegalAccessException iae) {
90                // good
91            }
92
93            Field field = target.getField("innerField");
94            try {
95                int x = field.getInt(instance);
96                if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
97                System.err.println("field get unexpectedly worked: " + x);
98            } catch (IllegalAccessException iae) {
99                // good
100            }
101        } catch (Exception ex) {
102            System.out.println("----- unexpected exception -----");
103            ex.printStackTrace();
104        }
105    }
106
107    public void run() {
108        Class target = Target.class;
109        Method meth = null;
110        Field field = null;
111        boolean excep;
112
113        try {
114            meth = target.getMethod("myMethod", new Class[] { int.class });
115
116            if (meth.getDeclaringClass() != target)
117                throw new RuntimeException();
118            printMethodInfo(meth);
119
120            meth = target.getMethod("myMethod", new Class[] { float.class });
121            printMethodInfo(meth);
122
123            meth = target.getMethod("myNoargMethod", (Class[]) null);
124            printMethodInfo(meth);
125
126            meth = target.getMethod("myMethod",
127                new Class[] { String[].class, float.class, char.class });
128            printMethodInfo(meth);
129
130            Target instance = new Target();
131            Object[] argList = new Object[] {
132                new String[] { "hi there" },
133                new Float(3.1415926f),
134                new Character('Q')
135            };
136            System.out.println("Before, float is "
137                + ((Float)argList[1]).floatValue());
138
139            Integer boxval;
140            boxval = (Integer) meth.invoke(instance, argList);
141            System.out.println("Result of invoke: " + boxval.intValue());
142
143            System.out.println("Calling no-arg void-return method");
144            meth = target.getMethod("myNoargMethod", (Class[]) null);
145            meth.invoke(instance, (Object[]) null);
146
147            /* try invoking a method that throws an exception */
148            meth = target.getMethod("throwingMethod", (Class[]) null);
149            try {
150                meth.invoke(instance, (Object[]) null);
151                System.out.println("GLITCH: didn't throw");
152            } catch (InvocationTargetException ite) {
153                System.out.println("Invoke got expected exception:");
154                System.out.println(ite.getClass().getName());
155                System.out.println(ite.getCause());
156            }
157            catch (Exception ex) {
158                System.out.println("GLITCH: invoke got wrong exception:");
159                ex.printStackTrace();
160            }
161            System.out.println("");
162
163
164            field = target.getField("string1");
165            if (field.getDeclaringClass() != target)
166                throw new RuntimeException();
167            printFieldInfo(field);
168            String strVal = (String) field.get(instance);
169            System.out.println("  string1 value is '" + strVal + "'");
170
171            showStrings(instance);
172
173            field.set(instance, new String("a new string"));
174            strVal = (String) field.get(instance);
175            System.out.println("  string1 value is now '" + strVal + "'");
176
177            showStrings(instance);
178
179            try {
180                field.set(instance, new Object());
181                System.out.println("WARNING: able to store Object into String");
182            }
183            catch (IllegalArgumentException iae) {
184                System.out.println("  got expected illegal obj store exc");
185            }
186
187
188            try {
189                String four;
190                field = target.getField("string4");
191                four = (String) field.get(instance);
192                System.out.println("WARNING: able to access string4: "
193                    + four);
194            }
195            catch (IllegalAccessException iae) {
196                System.out.println("  got expected access exc");
197            }
198            catch (NoSuchFieldException nsfe) {
199                System.out.println("  got the other expected access exc");
200            }
201            try {
202                String three;
203                field = target.getField("string3");
204                three = (String) field.get(this);
205                System.out.println("WARNING: able to get string3 in wrong obj: "
206                    + three);
207            }
208            catch (IllegalArgumentException iae) {
209                System.out.println("  got expected arg exc");
210            }
211
212            /*
213             * Try setting a field to null.
214             */
215            String four;
216            field = target.getDeclaredField("string3");
217            field.set(instance, null);
218
219            /*
220             * Do some stuff with long.
221             */
222            long longVal;
223            field = target.getField("pubLong");
224            longVal = field.getLong(instance);
225            System.out.println("pubLong initial value is " +
226                Long.toHexString(longVal));
227            field.setLong(instance, 0x9988776655443322L);
228            longVal = field.getLong(instance);
229            System.out.println("pubLong new value is " +
230                Long.toHexString(longVal));
231
232
233            field = target.getField("superInt");
234            if (field.getDeclaringClass() == target)
235                throw new RuntimeException();
236            printFieldInfo(field);
237            int intVal = field.getInt(instance);
238            System.out.println("  superInt value is " + intVal);
239            Integer boxedIntVal = (Integer) field.get(instance);
240            System.out.println("  superInt boxed is " + boxedIntVal);
241
242            field.set(instance, new Integer(20202));
243            intVal = field.getInt(instance);
244            System.out.println("  superInt value is now " + intVal);
245            field.setShort(instance, (short)30303);
246            intVal = field.getInt(instance);
247            System.out.println("  superInt value (from short) is now " +intVal);
248            field.setInt(instance, 40404);
249            intVal = field.getInt(instance);
250            System.out.println("  superInt value is now " + intVal);
251            try {
252                field.set(instance, new Long(123));
253                System.out.println("FAIL: expected exception not thrown");
254            }
255            catch (IllegalArgumentException iae) {
256                System.out.println("  got expected long->int failure");
257            }
258            try {
259                field.setLong(instance, 123);
260                System.out.println("FAIL: expected exception not thrown");
261            }
262            catch (IllegalArgumentException iae) {
263                System.out.println("  got expected long->int failure");
264            }
265            try {
266                field.set(instance, new String("abc"));
267                System.out.println("FAIL: expected exception not thrown");
268            }
269            catch (IllegalArgumentException iae) {
270                System.out.println("  got expected string->int failure");
271            }
272
273            try {
274                field.getShort(instance);
275                System.out.println("FAIL: expected exception not thrown");
276            }
277            catch (IllegalArgumentException iae) {
278                System.out.println("  got expected int->short failure");
279            }
280
281            field = target.getField("superClassInt");
282            printFieldInfo(field);
283            int superClassIntVal = field.getInt(instance);
284            System.out.println("  superClassInt value is " + superClassIntVal);
285
286            field = target.getField("staticDouble");
287            printFieldInfo(field);
288            double staticDoubleVal = field.getDouble(null);
289            System.out.println("  staticDoubleVal value is " + staticDoubleVal);
290
291            try {
292                field.getLong(instance);
293                System.out.println("FAIL: expected exception not thrown");
294            }
295            catch (IllegalArgumentException iae) {
296                System.out.println("  got expected double->long failure");
297            }
298
299            excep = false;
300            try {
301                field = target.getField("aPrivateInt");
302                printFieldInfo(field);
303            }
304            catch (NoSuchFieldException nsfe) {
305                System.out.println("as expected: aPrivateInt not found");
306                excep = true;
307            }
308            if (!excep)
309                System.out.println("BUG: got aPrivateInt");
310
311
312            field = target.getField("constantString");
313            printFieldInfo(field);
314            String val = (String) field.get(instance);
315            System.out.println("  Constant test value is " + val);
316
317
318            field = target.getField("cantTouchThis");
319            printFieldInfo(field);
320            intVal = field.getInt(instance);
321            System.out.println("  cantTouchThis is " + intVal);
322            try {
323                field.setInt(instance, 99);
324                System.out.println("ERROR: set-final succeeded");
325            } catch (IllegalAccessException iae) {
326                System.out.println("  got expected set-final failure");
327            }
328            intVal = field.getInt(instance);
329            System.out.println("  cantTouchThis is now " + intVal);
330
331            field.setAccessible(true);
332            field.setInt(instance, 87);     // exercise int version
333            field.set(instance, 88);        // exercise Object version
334            intVal = field.getInt(instance);
335            System.out.println("  cantTouchThis is now " + intVal);
336
337            Constructor<Target> cons;
338            Target targ;
339            Object[] args;
340
341            cons = target.getConstructor(new Class[] { int.class,float.class });
342            args = new Object[] { new Integer(7), new Float(3.3333) };
343            System.out.println("cons modifiers=" + cons.getModifiers());
344            targ = cons.newInstance(args);
345            targ.myMethod(17);
346
347        } catch (Exception ex) {
348            System.out.println("----- unexpected exception -----");
349            ex.printStackTrace();
350        }
351
352        System.out.println("ReflectTest done!");
353    }
354
355    public static void checkType() {
356        Method m;
357
358        try {
359            m = Collections.class.getDeclaredMethod("checkType",
360                            Object.class, Class.class);
361        } catch (NoSuchMethodException nsme) {
362            nsme.printStackTrace();
363            return;
364        }
365
366        m.setAccessible(true);
367        try {
368            m.invoke(null, new Object(), Object.class);
369        } catch (IllegalAccessException iae) {
370            iae.printStackTrace();
371            return;
372        } catch (InvocationTargetException ite) {
373            ite.printStackTrace();
374            return;
375        }
376
377        try {
378            System.out.println("checkType invoking null");
379            m.invoke(null, new Object(), int.class);
380            System.out.println("ERROR: should throw InvocationTargetException");
381        } catch (InvocationTargetException ite) {
382            System.out.println("checkType got expected exception");
383        } catch (IllegalAccessException iae) {
384            iae.printStackTrace();
385            return;
386        }
387    }
388
389    public static void checkInit() {
390        Class niuClass = NoisyInitUser.class;
391        Method[] methods;
392
393        methods = niuClass.getDeclaredMethods();
394        System.out.println("got methods");
395        /* neither NoisyInit nor NoisyInitUser should be initialized yet */
396        NoisyInitUser niu = new NoisyInitUser();
397        NoisyInit ni = new NoisyInit();
398
399        System.out.println("");
400    }
401
402
403    /*
404     * Test some generic type stuff.
405     */
406    public List<String> dummy;
407    public Map<Integer,String> fancyMethod(ArrayList<String> blah) { return null; }
408    public static void checkGeneric() {
409        Field field;
410        try {
411            field = Main.class.getField("dummy");
412        } catch (NoSuchFieldException nsfe) {
413            throw new RuntimeException(nsfe);
414        }
415        Type listType = field.getGenericType();
416        System.out.println("generic field: " + listType);
417
418        Method method;
419        try {
420            method = Main.class.getMethod("fancyMethod",
421                new Class[] { ArrayList.class });
422        } catch (NoSuchMethodException nsme) {
423            throw new RuntimeException(nsme);
424        }
425        Type[] parmTypes = method.getGenericParameterTypes();
426        Type ret = method.getGenericReturnType();
427        System.out.println("generic method " + method.getName() + " params='"
428            + stringifyTypeArray(parmTypes) + "' ret='" + ret + "'");
429
430        Constructor ctor;
431        try {
432            ctor = Main.class.getConstructor(new Class[] { ArrayList.class });
433        } catch (NoSuchMethodException nsme) {
434            throw new RuntimeException(nsme);
435        }
436        parmTypes = ctor.getGenericParameterTypes();
437        System.out.println("generic ctor " + ctor.getName() + " params='"
438            + stringifyTypeArray(parmTypes) + "'");
439    }
440
441    /*
442     * Convert an array of Type into a string.  Start with an array count.
443     */
444    private static String stringifyTypeArray(Type[] types) {
445        StringBuilder stb = new StringBuilder();
446        boolean first = true;
447
448        stb.append("[" + types.length + "]");
449
450        for (Type t: types) {
451            if (first) {
452                stb.append(" ");
453                first = false;
454            } else {
455                stb.append(", ");
456            }
457            stb.append(t.toString());
458        }
459
460        return stb.toString();
461    }
462
463
464    public static void main(String[] args) {
465        Main test = new Main();
466        test.run();
467
468        checkAccess();
469        checkType();
470        checkInit();
471        checkGeneric();
472    }
473}
474
475
476class SuperTarget {
477    public SuperTarget() {
478        System.out.println("SuperTarget constructor ()V");
479        superInt = 1010101;
480        superClassInt = 1010102;
481    }
482
483    public int myMethod(float floatArg) {
484        System.out.println("myMethod (F)I " + floatArg);
485        return 6;
486    }
487
488    public int superInt;
489    public static int superClassInt;
490}
491
492class Target extends SuperTarget {
493    public Target() {
494        System.out.println("Target constructor ()V");
495    }
496
497    public Target(int ii, float ff) {
498        System.out.println("Target constructor (IF)V : ii="
499            + ii + " ff=" + ff);
500        anInt = ii;
501    }
502
503    public int myMethod(int intarg) throws NullPointerException, IOException {
504        System.out.println("myMethod (I)I");
505        System.out.println(" arg=" + intarg + " anInt=" + anInt);
506        return 5;
507    }
508
509    public int myMethod(String[] strarg, float f, char c) {
510        System.out.println("myMethod: " + strarg[0] + " " + f + " " + c + " !");
511        return 7;
512    }
513
514    public static void myNoargMethod() {
515        System.out.println("myNoargMethod ()V");
516    }
517
518    public void throwingMethod() {
519        System.out.println("throwingMethod");
520        throw new NullPointerException("gratuitous throw!");
521    }
522
523    public void misc() {
524        System.out.println("misc");
525    }
526
527    public int anInt;
528    public String string1 = "hey";
529    public String string2 = "yo";
530    public String string3 = "there";
531    private String string4 = "naughty";
532    public static final String constantString = "a constant string";
533    private int aPrivateInt;
534
535    public final int cantTouchThis = 77;
536
537    public long pubLong = 0x1122334455667788L;
538
539    public static double staticDouble = 3.3;
540}
541
542class NoisyInit {
543    static {
544        System.out.println("NoisyInit is initializing");
545        //Throwable th = new Throwable();
546        //th.printStackTrace();
547    }
548}
549
550class NoisyInitUser {
551    static {
552        System.out.println("NoisyInitUser is initializing");
553    }
554    public void createNoisyInit(NoisyInit ni) {}
555}
556