blob: cbf6b7145e12d678c1406ead6ce60426472d141b [file] [log] [blame]
jeffhao5d1ac922011-09-29 17:41:15 -07001/*
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
17import other.OtherPackage;
18
19import java.lang.reflect.Field;
20
21/*
22 * Test field access through reflection.
23 */
24public 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 */
117class 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 */
130class 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
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700178 Class<?> accessExceptionClass = null; // art deliberately doesn't throw IllegalAccessException.
179
jeffhao5d1ac922011-09-29 17:41:15 -0700180 /*
181 * Get a public field from a class in the same package.
182 */
183 localInst.getValue(localPubByteField, samePkgInst, 'B', null);
184
185 /*
186 * Get a protected field from a class in the same package.
187 */
188 this.getValue(localProtByteField, samePkgInst, 'B', null);
189
190 /*
191 * Get a private field from a class in the same package.
192 */
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700193 this.getValue(localPrivFloatField, samePkgInst, 'F', accessExceptionClass);
jeffhao5d1ac922011-09-29 17:41:15 -0700194
195 /*
196 * Get a protected field from otherInst's superclass.
197 *
198 * We can get at "this.protShortField" but not
199 * "otherPkgInst.protShortField" because we can only access
200 * protected fields in instances of our class -- being a subclass
201 * of OtherPackage does not allow us to modify protected fields in
202 * all other subclasses of OtherPackage.
203 */
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700204 this.getValue(otherProtShortField, this, 'S', null);
205 this.getValue(otherProtShortField, otherPkgInst, 'S', accessExceptionClass);
206 this.getValue(otherPkgDoubleField, otherPkgInst, 'D', accessExceptionClass);
jeffhao5d1ac922011-09-29 17:41:15 -0700207
208 /*
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700209 * Null object.
jeffhao5d1ac922011-09-29 17:41:15 -0700210 */
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700211 localInst.getValue(localPubByteField, null, 'B', NullPointerException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700212
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700213 this.getValue(subProtLongField, null, 'J', NullPointerException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700214
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700215 this.getValue(localPrivFloatField, null, 'F', NullPointerException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700216
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700217 localInst.getValue(otherProtShortField, null, 'S', NullPointerException.class);
218 this.getValue(otherProtShortField, null, 'S', NullPointerException.class);
219 this.getValue(otherPkgDoubleField, null, 'D', NullPointerException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700220
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700221 localInst.getValue(otherProtShortField, null, 'Z', NullPointerException.class);
222 this.getValue(subProtLongField, null, 'Z', NullPointerException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700223
224 /*
225 * Valid object, wrong field type.
226 */
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700227 this.getValue(subProtLongField, this, 'J', null);
228 this.getValue(localProtByteField, samePkgInst, 'Z', IllegalArgumentException.class);
229 this.getValue(subProtLongField, this, 'Z', IllegalArgumentException.class);
230 this.getValue(localPrivFloatField, this, 'Z', IllegalArgumentException.class);
231 this.getValue(localPrivFloatField, this, 'Z', IllegalArgumentException.class);
232 localInst.getValue(otherProtShortField, otherPkgInst, 'Z', IllegalArgumentException.class);
233 this.getValue(otherProtShortField, otherPkgInst, 'Z', IllegalArgumentException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700234
235 /*
236 * Wrong object.
237 */
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700238 this.getValue(subProtLongField, plainObj, 'J', IllegalArgumentException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700239
240 /* wrong object + private field */
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700241 this.getValue(localPrivFloatField, plainObj, 'F', IllegalArgumentException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700242
243 /* wrong object + wrong field type */
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700244 this.getValue(subProtLongField, plainObj, 'Z', IllegalArgumentException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700245
246 /* wrong object + invalid access */
Elliott Hughesed1c1e32011-10-02 14:31:05 -0700247 localInst.getValue(otherProtShortField, plainObj, 'S', IllegalArgumentException.class);
248 this.getValue(otherProtShortField, plainObj, 'S', IllegalArgumentException.class);
jeffhao5d1ac922011-09-29 17:41:15 -0700249
250 System.out.println("good");
251 }
252
253 /*
254 * [this is a clone of Main.getValue() -- the class issuing the
255 * reflection call is significant]
256 */
257 public Object getValue(Field field, Object obj, char type,
258 Class expectedException) {
259
260 Object result = null;
261 try {
262 switch (type) {
263 case 'Z':
264 result = new Boolean(field.getBoolean(obj));
265 break;
266 case 'B':
267 result = new Byte(field.getByte(obj));
268 break;
269 case 'S':
270 result = new Short(field.getShort(obj));
271 break;
272 case 'C':
273 result = new Character(field.getChar(obj));
274 break;
275 case 'I':
276 result = new Integer(field.getInt(obj));
277 break;
278 case 'J':
279 result = new Long(field.getLong(obj));
280 break;
281 case 'F':
282 result = new Float(field.getFloat(obj));
283 break;
284 case 'D':
285 result = new Double(field.getDouble(obj));
286 break;
287 case 'L':
288 result = field.get(obj);
289 break;
290 default:
291 throw new RuntimeException("bad type '" + type + "'");
292 }
293
294 /* success; expected? */
295 if (expectedException != null) {
296 Throwable th = new Throwable();
297 System.err.println("ERROR: call succeeded, was expecting "
298 + expectedException);
299 th.printStackTrace();
300 }
301 } catch (Exception ex) {
302 if (expectedException == null) {
303 System.err.println("ERROR: call failed unexpectedly: "
304 + ex.getClass());
305 ex.printStackTrace();
306 } else {
307 if (!expectedException.equals(ex.getClass())) {
308 System.err.println("ERROR: incorrect exception: wanted "
309 + expectedException.getName() + ", got "
310 + ex.getClass());
311 ex.printStackTrace();
312 }
313 }
314 }
315
316 return result;
317 }
318
319}