Home | History | Annotate | Download | only in src
      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 
     17 import java.lang.reflect.*;
     18 import java.io.IOException;
     19 import java.util.Collections;
     20 import java.util.ArrayList;
     21 import java.util.List;
     22 import java.util.Map;
     23 
     24 /**
     25  * Reflection test.
     26  */
     27 public 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 
    596 class 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 
    612 class 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 
    662 class FieldNoisyInit {
    663   static {
    664     System.out.println("FieldNoisyInit is initializing");
    665     //Throwable th = new Throwable();
    666     //th.printStackTrace();
    667   }
    668 }
    669 
    670 class FieldNoisyInitUser {
    671   static {
    672     System.out.println("FieldNoisyInitUser is initializing");
    673   }
    674   public static int staticField;
    675   public static FieldNoisyInit noisy;
    676 }
    677 
    678 class MethodNoisyInit {
    679   static {
    680     System.out.println("MethodNoisyInit is initializing");
    681     //Throwable th = new Throwable();
    682     //th.printStackTrace();
    683   }
    684 }
    685 
    686 class MethodNoisyInitUser {
    687   static {
    688     System.out.println("MethodNoisyInitUser is initializing");
    689   }
    690   public static void staticMethod() {}
    691   public void createMethodNoisyInit(MethodNoisyInit ni) {}
    692 }
    693 
    694 class Thrower {
    695   public Thrower() throws UnsupportedOperationException {
    696     throw new UnsupportedOperationException();
    697   }
    698 }
    699