/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import other.OtherPackage; import java.lang.reflect.Field; /* * Test field access through reflection. */ public class Main { public static void main(String[] args) { SubOther.main(null); try { GetNonexistent.main(null); System.err.println("Not expected to succeed"); } catch (VerifyError fe) { // dalvik System.out.println("Got expected failure"); } catch (NoSuchFieldError nsfe) { // reference System.out.println("Got expected failure"); } } /* * Get the field specified by "field" from "obj". * * "type" determines which "get" call is made, e.g. 'B' turns into * field.getByte(). * * The "expectedException" must match the class of the exception thrown, * or be null if no exception was expected. * * On success, the boxed value retrieved is returned. */ public Object getValue(Field field, Object obj, char type, Class expectedException) { Object result = null; try { switch (type) { case 'Z': result = new Boolean(field.getBoolean(obj)); break; case 'B': result = new Byte(field.getByte(obj)); break; case 'S': result = new Short(field.getShort(obj)); break; case 'C': result = new Character(field.getChar(obj)); break; case 'I': result = new Integer(field.getInt(obj)); break; case 'J': result = new Long(field.getLong(obj)); break; case 'F': result = new Float(field.getFloat(obj)); break; case 'D': result = new Double(field.getDouble(obj)); break; case 'L': result = field.get(obj); break; default: throw new RuntimeException("bad type '" + type + "'"); } /* success; expected? */ if (expectedException != null) { Throwable th = new Throwable(); System.err.println("ERROR: call succeeded, was expecting " + expectedException); th.printStackTrace(); } } catch (Exception ex) { if (expectedException == null) { System.err.println("ERROR: call failed unexpectedly: " + ex.getClass()); ex.printStackTrace(); } else { if (!expectedException.equals(ex.getClass())) { System.err.println("ERROR: incorrect exception: wanted " + expectedException.getName() + ", got " + ex.getClass()); ex.printStackTrace(); } } } return result; } } /* * Local class with some fields. */ class SamePackage { public byte pubByteField; protected byte protByteField; protected Object protObjectField; private float privFloatField; } /* * This is a sub-class of OtherPackage, which should be allowed to access * the various protected fields. */ class SubOther extends OtherPackage { protected long protLongField = 0x1122334455667788L; /* * Perform the various tests. * * localInst.getValue() is performed using an instance of Main as the * source of the reflection call. otherInst.getValue() uses a subclass * of OtherPackage as the source. */ public static void main(String[] args) { SubOther subOther = new SubOther(); subOther.doTests(); } public void doTests() { Class localClass = SamePackage.class; Class otherClass = OtherPackage.class; Field localPubByteField, localProtByteField, localProtObjectField, localPrivFloatField; Field otherPubCharField, otherProtShortField, otherProtObjectField, otherPkgDoubleField; Field subProtLongField; Main localInst = new Main(); SamePackage samePkgInst = new SamePackage(); OtherPackage otherPkgInst = new OtherPackage(); Object plainObj = new Object(); /* * Locate the various fields. */ try { localPubByteField = localClass.getDeclaredField("pubByteField"); localProtByteField = localClass.getDeclaredField("protByteField"); localProtObjectField = localClass.getDeclaredField("protObjectField"); localPrivFloatField = localClass.getDeclaredField("privFloatField"); otherPubCharField = otherClass.getDeclaredField("pubCharField"); otherProtShortField = otherClass.getDeclaredField("protShortField"); otherProtObjectField = otherClass.getDeclaredField("protObjectField"); otherPkgDoubleField = otherClass.getDeclaredField("pkgDoubleField"); subProtLongField = getClass().getDeclaredField("protLongField"); } catch (NoSuchFieldException nsfe) { throw new RuntimeException(nsfe); } /* * Get a public field from a class in the same package. */ localInst.getValue(localPubByteField, samePkgInst, 'B', null); /* * Get a protected field from a class in the same package. */ this.getValue(localProtByteField, samePkgInst, 'B', null); /* * Get a private field from a class in the same package. */ this.getValue(localPrivFloatField, samePkgInst, 'F', IllegalAccessException.class); /* * Get a protected field from otherInst's superclass. * * We can get at "this.protShortField" but not * "otherPkgInst.protShortField" because we can only access * protected fields in instances of our class -- being a subclass * of OtherPackage does not allow us to modify protected fields in * all other subclasses of OtherPackage. */ this.getValue(otherProtShortField, this, 'S', null); this.getValue(otherProtShortField, otherPkgInst, 'S', IllegalAccessException.class); this.getValue(otherPkgDoubleField, otherPkgInst, 'D', IllegalAccessException.class); /* * Null object. Different exceptions based on which package * we would be trying to access and whether or not our object * has the correct type. */ localInst.getValue(localPubByteField, null, 'B', NullPointerException.class); this.getValue(subProtLongField, null, 'J', NullPointerException.class); this.getValue(localPrivFloatField, null, 'F', IllegalAccessException.class); localInst.getValue(otherProtShortField, null, 'S', IllegalAccessException.class); this.getValue(otherProtShortField, null, 'S', IllegalAccessException.class); this.getValue(otherPkgDoubleField, null, 'D', IllegalAccessException.class); localInst.getValue(otherProtShortField, null, 'Z', IllegalAccessException.class); /* -- Dalvik VM currently throws NPE this.getValue(subProtLongField, null, 'Z', IllegalArgumentException.class); */ /* * Valid object, wrong field type. */ this.getValue(subProtLongField, this, 'J', null); this.getValue(localProtByteField, samePkgInst, 'Z', IllegalArgumentException.class); this.getValue(subProtLongField, this, 'Z', IllegalArgumentException.class); this.getValue(localPrivFloatField, this, 'Z', IllegalAccessException.class); this.getValue(localPrivFloatField, this, 'Z', IllegalAccessException.class); localInst.getValue(otherProtShortField, otherPkgInst, 'Z', IllegalAccessException.class); this.getValue(otherProtShortField, otherPkgInst, 'Z', IllegalAccessException.class); /* * Wrong object. */ this.getValue(subProtLongField, plainObj, 'J', IllegalArgumentException.class); /* wrong object + private field */ this.getValue(localPrivFloatField, plainObj, 'F', IllegalAccessException.class); /* wrong object + wrong field type */ this.getValue(subProtLongField, plainObj, 'Z', IllegalArgumentException.class); /* wrong object + invalid access */ localInst.getValue(otherProtShortField, plainObj, 'S', IllegalAccessException.class); this.getValue(otherProtShortField, plainObj, 'S', IllegalAccessException.class); System.out.println("good"); } /* * [this is a clone of Main.getValue() -- the class issuing the * reflection call is significant] */ public Object getValue(Field field, Object obj, char type, Class expectedException) { Object result = null; try { switch (type) { case 'Z': result = new Boolean(field.getBoolean(obj)); break; case 'B': result = new Byte(field.getByte(obj)); break; case 'S': result = new Short(field.getShort(obj)); break; case 'C': result = new Character(field.getChar(obj)); break; case 'I': result = new Integer(field.getInt(obj)); break; case 'J': result = new Long(field.getLong(obj)); break; case 'F': result = new Float(field.getFloat(obj)); break; case 'D': result = new Double(field.getDouble(obj)); break; case 'L': result = field.get(obj); break; default: throw new RuntimeException("bad type '" + type + "'"); } /* success; expected? */ if (expectedException != null) { Throwable th = new Throwable(); System.err.println("ERROR: call succeeded, was expecting " + expectedException); th.printStackTrace(); } } catch (Exception ex) { if (expectedException == null) { System.err.println("ERROR: call failed unexpectedly: " + ex.getClass()); ex.printStackTrace(); } else { if (!expectedException.equals(ex.getClass())) { System.err.println("ERROR: incorrect exception: wanted " + expectedException.getName() + ", got " + ex.getClass()); ex.printStackTrace(); } } } return result; } }