| /* |
| * 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); |
| } |
| |
| Class<?> accessExceptionClass = null; // art deliberately doesn't throw IllegalAccessException. |
| |
| /* |
| * 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', accessExceptionClass); |
| |
| /* |
| * 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', accessExceptionClass); |
| this.getValue(otherPkgDoubleField, otherPkgInst, 'D', accessExceptionClass); |
| |
| /* |
| * Null object. |
| */ |
| localInst.getValue(localPubByteField, null, 'B', NullPointerException.class); |
| |
| this.getValue(subProtLongField, null, 'J', NullPointerException.class); |
| |
| this.getValue(localPrivFloatField, null, 'F', NullPointerException.class); |
| |
| localInst.getValue(otherProtShortField, null, 'S', NullPointerException.class); |
| this.getValue(otherProtShortField, null, 'S', NullPointerException.class); |
| this.getValue(otherPkgDoubleField, null, 'D', NullPointerException.class); |
| |
| localInst.getValue(otherProtShortField, null, 'Z', NullPointerException.class); |
| this.getValue(subProtLongField, null, 'Z', NullPointerException.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', IllegalArgumentException.class); |
| this.getValue(localPrivFloatField, this, 'Z', IllegalArgumentException.class); |
| localInst.getValue(otherProtShortField, otherPkgInst, 'Z', IllegalArgumentException.class); |
| this.getValue(otherProtShortField, otherPkgInst, 'Z', IllegalArgumentException.class); |
| |
| /* |
| * Wrong object. |
| */ |
| this.getValue(subProtLongField, plainObj, 'J', IllegalArgumentException.class); |
| |
| /* wrong object + private field */ |
| this.getValue(localPrivFloatField, plainObj, 'F', IllegalArgumentException.class); |
| |
| /* wrong object + wrong field type */ |
| this.getValue(subProtLongField, plainObj, 'Z', IllegalArgumentException.class); |
| |
| /* wrong object + invalid access */ |
| localInst.getValue(otherProtShortField, plainObj, 'S', IllegalArgumentException.class); |
| this.getValue(otherProtShortField, plainObj, 'S', IllegalArgumentException.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; |
| } |
| |
| } |