diff options
Diffstat (limited to 'test/064-field-access/src/Main.java')
-rw-r--r-- | test/064-field-access/src/Main.java | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/test/064-field-access/src/Main.java b/test/064-field-access/src/Main.java new file mode 100644 index 0000000000..c068d2369c --- /dev/null +++ b/test/064-field-access/src/Main.java @@ -0,0 +1,345 @@ +/* + * 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; + } + +} |