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