Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2008 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 other.OtherPackage;
     18 
     19 import java.lang.reflect.Field;
     20 
     21 /*
     22  * Test field access through reflection.
     23  */
     24 public class Main {
     25     public static void main(String[] args) {
     26         SubOther.main(null);
     27 
     28         try {
     29             GetNonexistent.main(null);
     30             System.err.println("Not expected to succeed");
     31         } catch (VerifyError fe) {
     32             // dalvik
     33             System.out.println("Got expected failure");
     34         } catch (NoSuchFieldError nsfe) {
     35             // reference
     36             System.out.println("Got expected failure");
     37         }
     38     }
     39 
     40     /*
     41      * Get the field specified by "field" from "obj".
     42      *
     43      * "type" determines which "get" call is made, e.g. 'B' turns into
     44      * field.getByte().
     45      *
     46      * The "expectedException" must match the class of the exception thrown,
     47      * or be null if no exception was expected.
     48      *
     49      * On success, the boxed value retrieved is returned.
     50      */
     51     public Object getValue(Field field, Object obj, char type,
     52             Class expectedException) {
     53 
     54         Object result = null;
     55         try {
     56             switch (type) {
     57             case 'Z':
     58                 result = new Boolean(field.getBoolean(obj));
     59                 break;
     60             case 'B':
     61                 result = new Byte(field.getByte(obj));
     62                 break;
     63             case 'S':
     64                 result = new Short(field.getShort(obj));
     65                 break;
     66             case 'C':
     67                 result = new Character(field.getChar(obj));
     68                 break;
     69             case 'I':
     70                 result = new Integer(field.getInt(obj));
     71                 break;
     72             case 'J':
     73                 result = new Long(field.getLong(obj));
     74                 break;
     75             case 'F':
     76                 result = new Float(field.getFloat(obj));
     77                 break;
     78             case 'D':
     79                 result = new Double(field.getDouble(obj));
     80                 break;
     81             case 'L':
     82                 result = field.get(obj);
     83                 break;
     84             default:
     85                 throw new RuntimeException("bad type '" + type + "'");
     86             }
     87 
     88             /* success; expected? */
     89             if (expectedException != null) {
     90                 Throwable th = new Throwable();
     91                 System.err.println("ERROR: call succeeded, was expecting "
     92                     + expectedException);
     93                 th.printStackTrace();
     94             }
     95         } catch (Exception ex) {
     96             if (expectedException == null) {
     97                 System.err.println("ERROR: call failed unexpectedly: "
     98                     + ex.getClass());
     99                 ex.printStackTrace();
    100             } else {
    101                 if (!expectedException.equals(ex.getClass())) {
    102                     System.err.println("ERROR: incorrect exception: wanted "
    103                         + expectedException.getName() + ", got "
    104                         + ex.getClass());
    105                     ex.printStackTrace();
    106                 }
    107             }
    108         }
    109 
    110         return result;
    111     }
    112 }
    113 
    114 /*
    115  * Local class with some fields.
    116  */
    117 class SamePackage {
    118     public byte pubByteField;
    119 
    120     protected byte protByteField;
    121     protected Object protObjectField;
    122 
    123     private float privFloatField;
    124 }
    125 
    126 /*
    127  * This is a sub-class of OtherPackage, which should be allowed to access
    128  * the various protected fields.
    129  */
    130 class SubOther extends OtherPackage {
    131 
    132     protected long protLongField = 0x1122334455667788L;
    133 
    134     /*
    135      * Perform the various tests.
    136      *
    137      * localInst.getValue() is performed using an instance of Main as the
    138      * source of the reflection call.  otherInst.getValue() uses a subclass
    139      * of OtherPackage as the source.
    140      */
    141     public static void main(String[] args) {
    142         SubOther subOther = new SubOther();
    143         subOther.doTests();
    144     }
    145 
    146     public void doTests() {
    147         Class localClass = SamePackage.class;
    148         Class otherClass = OtherPackage.class;
    149         Field localPubByteField, localProtByteField, localProtObjectField,
    150               localPrivFloatField;
    151         Field otherPubCharField, otherProtShortField, otherProtObjectField,
    152               otherPkgDoubleField;
    153         Field subProtLongField;
    154         Main localInst = new Main();
    155         SamePackage samePkgInst = new SamePackage();
    156         OtherPackage otherPkgInst = new OtherPackage();
    157         Object plainObj = new Object();
    158 
    159         /*
    160          * Locate the various fields.
    161          */
    162         try {
    163             localPubByteField = localClass.getDeclaredField("pubByteField");
    164             localProtByteField = localClass.getDeclaredField("protByteField");
    165             localProtObjectField = localClass.getDeclaredField("protObjectField");
    166             localPrivFloatField = localClass.getDeclaredField("privFloatField");
    167 
    168             otherPubCharField = otherClass.getDeclaredField("pubCharField");
    169             otherProtShortField = otherClass.getDeclaredField("protShortField");
    170             otherProtObjectField = otherClass.getDeclaredField("protObjectField");
    171             otherPkgDoubleField = otherClass.getDeclaredField("pkgDoubleField");
    172 
    173             subProtLongField = getClass().getDeclaredField("protLongField");
    174         } catch (NoSuchFieldException nsfe) {
    175             throw new RuntimeException(nsfe);
    176         }
    177 
    178         /*
    179          * Get a public field from a class in the same package.
    180          */
    181         localInst.getValue(localPubByteField, samePkgInst, 'B', null);
    182 
    183         /*
    184          * Get a protected field from a class in the same package.
    185          */
    186         this.getValue(localProtByteField, samePkgInst, 'B', null);
    187 
    188         /*
    189          * Get a private field from a class in the same package.
    190          */
    191         this.getValue(localPrivFloatField, samePkgInst, 'F',
    192             IllegalAccessException.class);
    193 
    194         /*
    195          * Get a protected field from otherInst's superclass.
    196          *
    197          * We can get at "this.protShortField" but not
    198          * "otherPkgInst.protShortField" because we can only access
    199          * protected fields in instances of our class -- being a subclass
    200          * of OtherPackage does not allow us to modify protected fields in
    201          * all other subclasses of OtherPackage.
    202          */
    203         this.getValue(otherProtShortField, this, 'S',
    204             null);
    205         this.getValue(otherProtShortField, otherPkgInst, 'S',
    206             IllegalAccessException.class);
    207         this.getValue(otherPkgDoubleField, otherPkgInst, 'D',
    208             IllegalAccessException.class);
    209 
    210         /*
    211          * Null object.  Different exceptions based on which package
    212          * we would be trying to access and whether or not our object
    213          * has the correct type.
    214          */
    215         localInst.getValue(localPubByteField, null, 'B',
    216             NullPointerException.class);
    217 
    218         this.getValue(subProtLongField, null, 'J',
    219             NullPointerException.class);
    220 
    221         this.getValue(localPrivFloatField, null, 'F',
    222             IllegalAccessException.class);
    223 
    224         localInst.getValue(otherProtShortField, null, 'S',
    225             IllegalAccessException.class);
    226         this.getValue(otherProtShortField, null, 'S',
    227             IllegalAccessException.class);
    228         this.getValue(otherPkgDoubleField, null, 'D',
    229             IllegalAccessException.class);
    230 
    231         localInst.getValue(otherProtShortField, null, 'Z',
    232             IllegalAccessException.class);
    233         /* -- Dalvik VM currently throws NPE
    234         this.getValue(subProtLongField, null, 'Z',
    235             IllegalArgumentException.class);
    236         */
    237 
    238         /*
    239          * Valid object, wrong field type.
    240          */
    241         this.getValue(subProtLongField, this, 'J',
    242             null);
    243         this.getValue(localProtByteField, samePkgInst, 'Z',
    244             IllegalArgumentException.class);
    245         this.getValue(subProtLongField, this, 'Z',
    246             IllegalArgumentException.class);
    247         this.getValue(localPrivFloatField, this, 'Z',
    248             IllegalAccessException.class);
    249         this.getValue(localPrivFloatField, this, 'Z',
    250             IllegalAccessException.class);
    251         localInst.getValue(otherProtShortField, otherPkgInst, 'Z',
    252             IllegalAccessException.class);
    253         this.getValue(otherProtShortField, otherPkgInst, 'Z',
    254             IllegalAccessException.class);
    255 
    256         /*
    257          * Wrong object.
    258          */
    259         this.getValue(subProtLongField, plainObj, 'J',
    260             IllegalArgumentException.class);
    261 
    262         /* wrong object + private field */
    263         this.getValue(localPrivFloatField, plainObj, 'F',
    264             IllegalAccessException.class);
    265 
    266         /* wrong object + wrong field type */
    267         this.getValue(subProtLongField, plainObj, 'Z',
    268             IllegalArgumentException.class);
    269 
    270         /* wrong object + invalid access */
    271         localInst.getValue(otherProtShortField, plainObj, 'S',
    272             IllegalAccessException.class);
    273         this.getValue(otherProtShortField, plainObj, 'S',
    274             IllegalAccessException.class);
    275 
    276         System.out.println("good");
    277     }
    278 
    279     /*
    280      * [this is a clone of Main.getValue() -- the class issuing the
    281      * reflection call is significant]
    282      */
    283     public Object getValue(Field field, Object obj, char type,
    284             Class expectedException) {
    285 
    286         Object result = null;
    287         try {
    288             switch (type) {
    289             case 'Z':
    290                 result = new Boolean(field.getBoolean(obj));
    291                 break;
    292             case 'B':
    293                 result = new Byte(field.getByte(obj));
    294                 break;
    295             case 'S':
    296                 result = new Short(field.getShort(obj));
    297                 break;
    298             case 'C':
    299                 result = new Character(field.getChar(obj));
    300                 break;
    301             case 'I':
    302                 result = new Integer(field.getInt(obj));
    303                 break;
    304             case 'J':
    305                 result = new Long(field.getLong(obj));
    306                 break;
    307             case 'F':
    308                 result = new Float(field.getFloat(obj));
    309                 break;
    310             case 'D':
    311                 result = new Double(field.getDouble(obj));
    312                 break;
    313             case 'L':
    314                 result = field.get(obj);
    315                 break;
    316             default:
    317                 throw new RuntimeException("bad type '" + type + "'");
    318             }
    319 
    320             /* success; expected? */
    321             if (expectedException != null) {
    322                 Throwable th = new Throwable();
    323                 System.err.println("ERROR: call succeeded, was expecting "
    324                     + expectedException);
    325                 th.printStackTrace();
    326             }
    327         } catch (Exception ex) {
    328             if (expectedException == null) {
    329                 System.err.println("ERROR: call failed unexpectedly: "
    330                     + ex.getClass());
    331                 ex.printStackTrace();
    332             } else {
    333                 if (!expectedException.equals(ex.getClass())) {
    334                     System.err.println("ERROR: incorrect exception: wanted "
    335                         + expectedException.getName() + ", got "
    336                         + ex.getClass());
    337                     ex.printStackTrace();
    338                 }
    339             }
    340         }
    341 
    342         return result;
    343     }
    344 
    345 }
    346