Main.java revision 63f5b9e8f660ae761901072821ece30d87891644
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import java.lang.reflect.*;
18import java.io.IOException;
19import java.util.Collections;
20import java.util.ArrayList;
21import java.util.List;
22import java.util.Map;
23
24/**
25 * Reflection test.
26 */
27public class Main {
28    private static boolean FULL_ACCESS_CHECKS = false;  // b/5861201
29    public Main() {}
30    public Main(ArrayList<Integer> stuff) {}
31
32    void printMethodInfo(Method meth) {
33        Class[] params, exceptions;
34        int i;
35
36        System.out.println("Method name is " + meth.getName());
37        System.out.println(" Declaring class is "
38            + meth.getDeclaringClass().getName());
39        params = meth.getParameterTypes();
40        for (i = 0; i < params.length; i++)
41            System.out.println(" Arg " + i + ": " + params[i].getName());
42        exceptions = meth.getExceptionTypes();
43        for (i = 0; i < exceptions.length; i++)
44            System.out.println(" Exc " + i + ": " + exceptions[i].getName());
45        System.out.println(" Return type is " + meth.getReturnType().getName());
46        System.out.println(" Access flags are 0x"
47            + Integer.toHexString(meth.getModifiers()));
48        //System.out.println(" GenericStr is " + meth.toGenericString());
49    }
50
51    void printFieldInfo(Field field) {
52        System.out.println("Field name is " + field.getName());
53        System.out.println(" Declaring class is "
54            + field.getDeclaringClass().getName());
55        System.out.println(" Field type is " + field.getType().getName());
56        System.out.println(" Access flags are 0x"
57            + Integer.toHexString(field.getModifiers()));
58    }
59
60    private void showStrings(Target instance)
61        throws NoSuchFieldException, IllegalAccessException {
62
63        Class target = Target.class;
64        String one, two, three, four;
65        Field field = null;
66
67        field = target.getField("string1");
68        one = (String) field.get(instance);
69
70        field = target.getField("string2");
71        two = (String) field.get(instance);
72
73        field = target.getField("string3");
74        three = (String) field.get(instance);
75
76        System.out.println("  ::: " + one + ":" + two + ":" + three);
77    }
78
79    public static void checkAccess() {
80        try {
81            Class target = otherpackage.Other.class;
82            Object instance = new otherpackage.Other();
83            Method meth;
84
85            meth = target.getMethod("publicMethod", (Class[]) null);
86            meth.invoke(instance);
87
88            try {
89                meth = target.getMethod("packageMethod", (Class[]) null);
90                System.err.println("succeeded on package-scope method");
91            } catch (NoSuchMethodException nsme) {
92                // good
93            }
94
95
96            instance = otherpackage.Other.getInnerClassInstance();
97            target = instance.getClass();
98            meth = target.getMethod("innerMethod", (Class[]) null);
99            try {
100                if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
101                meth.invoke(instance);
102                System.err.println("inner-method invoke unexpectedly worked");
103            } catch (IllegalAccessException iae) {
104                // good
105            }
106
107            Field field = target.getField("innerField");
108            try {
109                int x = field.getInt(instance);
110                if (!FULL_ACCESS_CHECKS) { throw new IllegalAccessException(); }
111                System.err.println("field get unexpectedly worked: " + x);
112            } catch (IllegalAccessException iae) {
113                // good
114            }
115        } catch (Exception ex) {
116            System.out.println("----- unexpected exception -----");
117            ex.printStackTrace();
118        }
119    }
120
121    public void run() {
122        Class target = Target.class;
123        Method meth = null;
124        Field field = null;
125        boolean excep;
126
127        try {
128            meth = target.getMethod("myMethod", new Class[] { int.class });
129
130            if (meth.getDeclaringClass() != target)
131                throw new RuntimeException();
132            printMethodInfo(meth);
133
134            meth = target.getMethod("myMethod", new Class[] { float.class });
135            printMethodInfo(meth);
136
137            meth = target.getMethod("myNoargMethod", (Class[]) null);
138            printMethodInfo(meth);
139
140            meth = target.getMethod("myMethod",
141                new Class[] { String[].class, float.class, char.class });
142            printMethodInfo(meth);
143
144            Target instance = new Target();
145            Object[] argList = new Object[] {
146                new String[] { "hi there" },
147                new Float(3.1415926f),
148                new Character('Q')
149            };
150            System.out.println("Before, float is "
151                + ((Float)argList[1]).floatValue());
152
153            Integer boxval;
154            boxval = (Integer) meth.invoke(instance, argList);
155            System.out.println("Result of invoke: " + boxval.intValue());
156
157            System.out.println("Calling no-arg void-return method");
158            meth = target.getMethod("myNoargMethod", (Class[]) null);
159            meth.invoke(instance, (Object[]) null);
160
161            /* try invoking a method that throws an exception */
162            meth = target.getMethod("throwingMethod", (Class[]) null);
163            try {
164                meth.invoke(instance, (Object[]) null);
165                System.out.println("GLITCH: didn't throw");
166            } catch (InvocationTargetException ite) {
167                System.out.println("Invoke got expected exception:");
168                System.out.println(ite.getClass().getName());
169                System.out.println(ite.getCause());
170            }
171            catch (Exception ex) {
172                System.out.println("GLITCH: invoke got wrong exception:");
173                ex.printStackTrace();
174            }
175            System.out.println("");
176
177
178            field = target.getField("string1");
179            if (field.getDeclaringClass() != target)
180                throw new RuntimeException();
181            printFieldInfo(field);
182            String strVal = (String) field.get(instance);
183            System.out.println("  string1 value is '" + strVal + "'");
184
185            showStrings(instance);
186
187            field.set(instance, new String("a new string"));
188            strVal = (String) field.get(instance);
189            System.out.println("  string1 value is now '" + strVal + "'");
190
191            showStrings(instance);
192
193            try {
194                field.set(instance, new Object());
195                System.out.println("WARNING: able to store Object into String");
196            }
197            catch (IllegalArgumentException iae) {
198                System.out.println("  got expected illegal obj store exc");
199            }
200
201
202            try {
203                String four;
204                field = target.getField("string4");
205                four = (String) field.get(instance);
206                System.out.println("WARNING: able to access string4: "
207                    + four);
208            }
209            catch (IllegalAccessException iae) {
210                System.out.println("  got expected access exc");
211            }
212            catch (NoSuchFieldException nsfe) {
213                System.out.println("  got the other expected access exc");
214            }
215            try {
216                String three;
217                field = target.getField("string3");
218                three = (String) field.get(this);
219                System.out.println("WARNING: able to get string3 in wrong obj: "
220                    + three);
221            }
222            catch (IllegalArgumentException iae) {
223                System.out.println("  got expected arg exc");
224            }
225
226            /*
227             * Try setting a field to null.
228             */
229            String four;
230            field = target.getDeclaredField("string3");
231            field.set(instance, null);
232
233            /*
234             * Do some stuff with long.
235             */
236            long longVal;
237            field = target.getField("pubLong");
238            longVal = field.getLong(instance);
239            System.out.println("pubLong initial value is " +
240                Long.toHexString(longVal));
241            field.setLong(instance, 0x9988776655443322L);
242            longVal = field.getLong(instance);
243            System.out.println("pubLong new value is " +
244                Long.toHexString(longVal));
245
246
247            field = target.getField("superInt");
248            if (field.getDeclaringClass() == target)
249                throw new RuntimeException();
250            printFieldInfo(field);
251            int intVal = field.getInt(instance);
252            System.out.println("  superInt value is " + intVal);
253            Integer boxedIntVal = (Integer) field.get(instance);
254            System.out.println("  superInt boxed is " + boxedIntVal);
255
256            field.set(instance, new Integer(20202));
257            intVal = field.getInt(instance);
258            System.out.println("  superInt value is now " + intVal);
259            field.setShort(instance, (short)30303);
260            intVal = field.getInt(instance);
261            System.out.println("  superInt value (from short) is now " +intVal);
262            field.setInt(instance, 40404);
263            intVal = field.getInt(instance);
264            System.out.println("  superInt value is now " + intVal);
265            try {
266                field.set(instance, new Long(123));
267                System.out.println("FAIL: expected exception not thrown");
268            }
269            catch (IllegalArgumentException iae) {
270                System.out.println("  got expected long->int failure");
271            }
272            try {
273                field.setLong(instance, 123);
274                System.out.println("FAIL: expected exception not thrown");
275            }
276            catch (IllegalArgumentException iae) {
277                System.out.println("  got expected long->int failure");
278            }
279            try {
280                field.set(instance, new String("abc"));
281                System.out.println("FAIL: expected exception not thrown");
282            }
283            catch (IllegalArgumentException iae) {
284                System.out.println("  got expected string->int failure");
285            }
286
287            try {
288                field.getShort(instance);
289                System.out.println("FAIL: expected exception not thrown");
290            }
291            catch (IllegalArgumentException iae) {
292                System.out.println("  got expected int->short failure");
293            }
294
295            field = target.getField("superClassInt");
296            printFieldInfo(field);
297            int superClassIntVal = field.getInt(instance);
298            System.out.println("  superClassInt value is " + superClassIntVal);
299
300            field = target.getField("staticDouble");
301            printFieldInfo(field);
302            double staticDoubleVal = field.getDouble(null);
303            System.out.println("  staticDoubleVal value is " + staticDoubleVal);
304
305            try {
306                field.getLong(instance);
307                System.out.println("FAIL: expected exception not thrown");
308            }
309            catch (IllegalArgumentException iae) {
310                System.out.println("  got expected double->long failure");
311            }
312
313            excep = false;
314            try {
315                field = target.getField("aPrivateInt");
316                printFieldInfo(field);
317            }
318            catch (NoSuchFieldException nsfe) {
319                System.out.println("as expected: aPrivateInt not found");
320                excep = true;
321            }
322            if (!excep)
323                System.out.println("BUG: got aPrivateInt");
324
325
326            field = target.getField("constantString");
327            printFieldInfo(field);
328            String val = (String) field.get(instance);
329            System.out.println("  Constant test value is " + val);
330
331
332            field = target.getField("cantTouchThis");
333            printFieldInfo(field);
334            intVal = field.getInt(instance);
335            System.out.println("  cantTouchThis is " + intVal);
336            try {
337                field.setInt(instance, 99);
338                System.out.println("ERROR: set-final did not throw exception");
339            } catch (IllegalAccessException iae) {
340                System.out.println("  as expected: set-final throws exception");
341            }
342            intVal = field.getInt(instance);
343            System.out.println("  cantTouchThis is still " + intVal);
344
345            System.out.println("  " + field + " accessible=" + field.isAccessible());
346            field.setAccessible(true);
347            System.out.println("  " + field + " accessible=" + field.isAccessible());
348            field.setInt(instance, 87);     // exercise int version
349            intVal = field.getInt(instance);
350            System.out.println("  cantTouchThis is now " + intVal);
351            field.set(instance, 88);        // exercise Object version
352            intVal = field.getInt(instance);
353            System.out.println("  cantTouchThis is now " + intVal);
354
355            Constructor<Target> cons;
356            Target targ;
357            Object[] args;
358
359            cons = target.getConstructor(new Class[] { int.class,float.class });
360            args = new Object[] { new Integer(7), new Float(3.3333) };
361            System.out.println("cons modifiers=" + cons.getModifiers());
362            targ = cons.newInstance(args);
363            targ.myMethod(17);
364
365            try {
366                Thrower thrower = Thrower.class.newInstance();
367                System.out.println("ERROR: Class.newInstance did not throw exception");
368            } catch (UnsupportedOperationException uoe) {
369                System.out.println("got expected exception for Class.newInstance");
370            } catch (Exception e) {
371                System.out.println("ERROR: Class.newInstance got unexpected exception: " +
372                                   e.getClass().getName());
373            }
374
375            try {
376                Constructor<Thrower> constructor = Thrower.class.getDeclaredConstructor();
377                Thrower thrower = constructor.newInstance();
378                System.out.println("ERROR: Constructor.newInstance did not throw exception");
379            } catch (InvocationTargetException ite) {
380                System.out.println("got expected exception for Constructor.newInstance");
381            } catch (Exception e) {
382                System.out.println("ERROR: Constructor.newInstance got unexpected exception: " +
383                                   e.getClass().getName());
384            }
385
386        } catch (Exception ex) {
387            System.out.println("----- unexpected exception -----");
388            ex.printStackTrace();
389        }
390
391        System.out.println("ReflectTest done!");
392    }
393
394    public static void checkType() {
395        Method m;
396
397        try {
398            m = Collections.class.getDeclaredMethod("checkType",
399                            Object.class, Class.class);
400        } catch (NoSuchMethodException nsme) {
401            nsme.printStackTrace();
402            return;
403        }
404        System.out.println(m + " accessible=" + m.isAccessible());
405        m.setAccessible(true);
406        System.out.println(m + " accessible=" + m.isAccessible());
407        try {
408            m.invoke(null, new Object(), Object.class);
409        } catch (IllegalAccessException iae) {
410            iae.printStackTrace();
411            return;
412        } catch (InvocationTargetException ite) {
413            ite.printStackTrace();
414            return;
415        }
416
417        try {
418            String s = "Should be ignored";
419            m.invoke(s, new Object(), Object.class);
420        } catch (IllegalAccessException iae) {
421            iae.printStackTrace();
422            return;
423        } catch (InvocationTargetException ite) {
424            ite.printStackTrace();
425            return;
426        }
427
428        try {
429            System.out.println("checkType invoking null");
430            m.invoke(null, new Object(), int.class);
431            System.out.println("ERROR: should throw InvocationTargetException");
432        } catch (InvocationTargetException ite) {
433            System.out.println("checkType got expected exception");
434        } catch (IllegalAccessException iae) {
435            iae.printStackTrace();
436            return;
437        }
438    }
439
440    public static void checkClinitForFields() throws Exception {
441      // Loading a class constant shouldn't run <clinit>.
442      System.out.println("calling const-class FieldNoisyInitUser.class");
443      Class niuClass = FieldNoisyInitUser.class;
444      System.out.println("called const-class FieldNoisyInitUser.class");
445
446      // Getting the declared fields doesn't run <clinit>.
447      Field[] fields = niuClass.getDeclaredFields();
448      System.out.println("got fields");
449
450      Field field = niuClass.getField("staticField");
451      System.out.println("got field");
452      field.get(null);
453      System.out.println("read field value");
454
455      // FieldNoisyInitUser should now be initialized, but FieldNoisyInit shouldn't be initialized yet.
456      FieldNoisyInitUser niu = new FieldNoisyInitUser();
457      FieldNoisyInit ni = new FieldNoisyInit();
458
459      System.out.println("");
460    }
461
462    public static void checkClinitForMethods() throws Exception {
463      // Loading a class constant shouldn't run <clinit>.
464      System.out.println("calling const-class MethodNoisyInitUser.class");
465      Class niuClass = MethodNoisyInitUser.class;
466      System.out.println("called const-class MethodNoisyInitUser.class");
467
468      // Getting the declared methods doesn't run <clinit>.
469      Method[] methods = niuClass.getDeclaredMethods();
470      System.out.println("got methods");
471
472      Method method = niuClass.getMethod("staticMethod", (Class[]) null);
473      System.out.println("got method");
474      method.invoke(null);
475      System.out.println("invoked method");
476
477      // MethodNoisyInitUser should now be initialized, but MethodNoisyInit shouldn't be initialized yet.
478      MethodNoisyInitUser niu = new MethodNoisyInitUser();
479      MethodNoisyInit ni = new MethodNoisyInit();
480
481      System.out.println("");
482    }
483
484
485    /*
486     * Test some generic type stuff.
487     */
488    public List<String> dummy;
489    public Map<Integer,String> fancyMethod(ArrayList<String> blah) { return null; }
490    public static void checkGeneric() {
491        Field field;
492        try {
493            field = Main.class.getField("dummy");
494        } catch (NoSuchFieldException nsfe) {
495            throw new RuntimeException(nsfe);
496        }
497        Type listType = field.getGenericType();
498        System.out.println("generic field: " + listType);
499
500        Method method;
501        try {
502            method = Main.class.getMethod("fancyMethod",
503                new Class[] { ArrayList.class });
504        } catch (NoSuchMethodException nsme) {
505            throw new RuntimeException(nsme);
506        }
507        Type[] parmTypes = method.getGenericParameterTypes();
508        Type ret = method.getGenericReturnType();
509        System.out.println("generic method " + method.getName() + " params='"
510            + stringifyTypeArray(parmTypes) + "' ret='" + ret + "'");
511
512        Constructor ctor;
513        try {
514            ctor = Main.class.getConstructor(new Class[] { ArrayList.class });
515        } catch (NoSuchMethodException nsme) {
516            throw new RuntimeException(nsme);
517        }
518        parmTypes = ctor.getGenericParameterTypes();
519        System.out.println("generic ctor " + ctor.getName() + " params='"
520            + stringifyTypeArray(parmTypes) + "'");
521    }
522
523    /*
524     * Convert an array of Type into a string.  Start with an array count.
525     */
526    private static String stringifyTypeArray(Type[] types) {
527        StringBuilder stb = new StringBuilder();
528        boolean first = true;
529
530        stb.append("[" + types.length + "]");
531
532        for (Type t: types) {
533            if (first) {
534                stb.append(" ");
535                first = false;
536            } else {
537                stb.append(", ");
538            }
539            stb.append(t.toString());
540        }
541
542        return stb.toString();
543    }
544
545    public static void checkUnique() {
546        Field field1, field2;
547        try {
548            field1 = Main.class.getField("dummy");
549            field2 = Main.class.getField("dummy");
550        } catch (NoSuchFieldException nsfe) {
551            throw new RuntimeException(nsfe);
552        }
553        if (field1 == field2) {
554            System.out.println("ERROR: fields shouldn't have reference equality");
555        } else {
556            System.out.println("fields are unique");
557        }
558        if (field1.hashCode() == field2.hashCode() && field1.equals(field2)) {
559            System.out.println("fields are .equals");
560        } else {
561            System.out.println("ERROR: fields fail equality");
562        }
563        Method method1, method2;
564        try {
565            method1 = Main.class.getMethod("fancyMethod", new Class[] { ArrayList.class });
566            method2 = Main.class.getMethod("fancyMethod", new Class[] { ArrayList.class });
567        } catch (NoSuchMethodException nsme) {
568            throw new RuntimeException(nsme);
569        }
570        if (method1 == method2) {
571            System.out.println("ERROR: methods shouldn't have reference equality");
572        } else {
573            System.out.println("methods are unique");
574        }
575        if (method1.hashCode() == method2.hashCode() && method1.equals(method2)) {
576            System.out.println("methods are .equals");
577        } else {
578            System.out.println("ERROR: methods fail equality");
579        }
580    }
581
582    public static void main(String[] args) throws Exception {
583        Main test = new Main();
584        test.run();
585
586        checkAccess();
587        checkType();
588        checkClinitForFields();
589        checkClinitForMethods();
590        checkGeneric();
591        checkUnique();
592    }
593}
594
595
596class SuperTarget {
597    public SuperTarget() {
598        System.out.println("SuperTarget constructor ()V");
599        superInt = 1010101;
600        superClassInt = 1010102;
601    }
602
603    public int myMethod(float floatArg) {
604        System.out.println("myMethod (F)I " + floatArg);
605        return 6;
606    }
607
608    public int superInt;
609    public static int superClassInt;
610}
611
612class Target extends SuperTarget {
613    public Target() {
614        System.out.println("Target constructor ()V");
615    }
616
617    public Target(int ii, float ff) {
618        System.out.println("Target constructor (IF)V : ii="
619            + ii + " ff=" + ff);
620        anInt = ii;
621    }
622
623    public int myMethod(int intarg) throws NullPointerException, IOException {
624        System.out.println("myMethod (I)I");
625        System.out.println(" arg=" + intarg + " anInt=" + anInt);
626        return 5;
627    }
628
629    public int myMethod(String[] strarg, float f, char c) {
630        System.out.println("myMethod: " + strarg[0] + " " + f + " " + c + " !");
631        return 7;
632    }
633
634    public static void myNoargMethod() {
635        System.out.println("myNoargMethod ()V");
636    }
637
638    public void throwingMethod() {
639        System.out.println("throwingMethod");
640        throw new NullPointerException("gratuitous throw!");
641    }
642
643    public void misc() {
644        System.out.println("misc");
645    }
646
647    public int anInt;
648    public String string1 = "hey";
649    public String string2 = "yo";
650    public String string3 = "there";
651    private String string4 = "naughty";
652    public static final String constantString = "a constant string";
653    private int aPrivateInt;
654
655    public final int cantTouchThis = 77;
656
657    public long pubLong = 0x1122334455667788L;
658
659    public static double staticDouble = 3.3;
660}
661
662class FieldNoisyInit {
663  static {
664    System.out.println("FieldNoisyInit is initializing");
665    //Throwable th = new Throwable();
666    //th.printStackTrace();
667  }
668}
669
670class FieldNoisyInitUser {
671  static {
672    System.out.println("FieldNoisyInitUser is initializing");
673  }
674  public static int staticField;
675  public static FieldNoisyInit noisy;
676}
677
678class MethodNoisyInit {
679  static {
680    System.out.println("MethodNoisyInit is initializing");
681    //Throwable th = new Throwable();
682    //th.printStackTrace();
683  }
684}
685
686class MethodNoisyInitUser {
687  static {
688    System.out.println("MethodNoisyInitUser is initializing");
689  }
690  public static void staticMethod() {}
691  public void createMethodNoisyInit(MethodNoisyInit ni) {}
692}
693
694class Thrower {
695  public Thrower() throws UnsupportedOperationException {
696    throw new UnsupportedOperationException();
697  }
698}
699