blob: 7dfb6f507da29d410483c153765b1cc62795086d [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
17/**
18 * Class loader test.
19 */
20public class Main {
21 /**
22 * Main entry point.
23 */
24 public static void main(String[] args) {
25 FancyLoader loader;
26
27 loader = new FancyLoader(ClassLoader.getSystemClassLoader());
28 //System.out.println("SYSTEM: " + ClassLoader.getSystemClassLoader());
29 //System.out.println("ALTERN: " + loader);
30
31 /*
32 * This statement has no effect on this program, but it can
33 * change the point where a LinkageException is thrown in
34 * testImplement(). When this is present the "reference
35 * implementation" throws an exception from Class.newInstance(),
36 * when it's absent the exception is deferred until the first time
37 * we call a method that isn't actually implemented.
38 *
39 * This isn't the class that fails -- it's a class with the same
40 * name in the "fancy" class loader -- but the VM thinks it has a
41 * reference to one of these; presumably the difference is that
42 * without this the VM finds itself holding a reference to an
43 * instance of an uninitialized class.
44 */
45 System.out.println("base: " + DoubledImplement.class);
46 System.out.println("base2: " + DoubledImplement2.class);
47
48 /*
49 * Run tests.
50 */
51 testAccess1(loader);
52 testAccess2(loader);
53 testAccess3(loader);
54
55 testExtend(loader);
56 testExtendOkay(loader);
57 testInterface(loader);
58 testAbstract(loader);
59 testImplement(loader);
60 testIfaceImplement(loader);
61 }
62
63 /**
64 * See if we can load a class that isn't public to us. We should be
65 * able to load it but not instantiate it.
66 */
67 static void testAccess1(ClassLoader loader) {
68 Class altClass;
69
70 try {
71 altClass = loader.loadClass("Inaccessible1");
72 } catch (ClassNotFoundException cnfe) {
73 System.err.println("loadClass failed");
74 cnfe.printStackTrace();
75 return;
76 }
77
78 /* instantiate */
79 Object obj;
80 try {
81 obj = altClass.newInstance();
82 System.err.println("ERROR: Inaccessible1 was accessible");
83 } catch (InstantiationException ie) {
84 System.err.println("newInstance failed: " + ie);
85 return;
86 } catch (IllegalAccessException iae) {
87 System.out.println("Got expected access exception #1");
88 //System.out.println("+++ " + iae);
89 return;
90 }
91 }
92
93 /**
94 * See if we can load a class whose base class is not accessible to it
95 * (though the base *is* accessible to us).
96 */
97 static void testAccess2(ClassLoader loader) {
98 Class altClass;
99
100 try {
101 altClass = loader.loadClass("Inaccessible2");
Brian Carlstrom4d9716c2012-01-30 01:49:33 -0800102 System.err.println("ERROR: Inaccessible2 was accessible: " + altClass);
jeffhao5d1ac922011-09-29 17:41:15 -0700103 } catch (ClassNotFoundException cnfe) {
104 Throwable cause = cnfe.getCause();
105 if (cause instanceof IllegalAccessError) {
106 System.out.println("Got expected CNFE/IAE #2");
107 } else {
108 System.err.println("Got unexpected CNFE/IAE #2");
109 cnfe.printStackTrace();
110 }
111 }
112 }
113
114 /**
115 * See if we can load a class with an inaccessible interface.
116 */
117 static void testAccess3(ClassLoader loader) {
118 Class altClass;
119
120 try {
121 altClass = loader.loadClass("Inaccessible3");
Brian Carlstrom4d9716c2012-01-30 01:49:33 -0800122 System.err.println("ERROR: Inaccessible3 was accessible: " + altClass);
jeffhao5d1ac922011-09-29 17:41:15 -0700123 } catch (ClassNotFoundException cnfe) {
124 Throwable cause = cnfe.getCause();
125 if (cause instanceof IllegalAccessError) {
126 System.out.println("Got expected CNFE/IAE #3");
127 } else {
128 System.err.println("Got unexpected CNFE/IAE #3");
129 cnfe.printStackTrace();
130 }
131 }
132 }
133
134 /**
135 * Test a doubled class that extends the base class.
136 */
137 static void testExtend(ClassLoader loader) {
138 Class doubledExtendClass;
139 Object obj;
140
141 /* get the "alternate" version of DoubledExtend */
142 try {
143 doubledExtendClass = loader.loadClass("DoubledExtend");
144 //System.out.println("+++ DoubledExtend is " + doubledExtendClass
145 // + " in " + doubledExtendClass.getClassLoader());
146 } catch (ClassNotFoundException cnfe) {
147 System.err.println("loadClass failed: " + cnfe);
148 return;
149 }
150
151 /* instantiate */
152 try {
153 obj = doubledExtendClass.newInstance();
154 } catch (InstantiationException ie) {
155 System.err.println("newInstance failed: " + ie);
156 return;
157 } catch (IllegalAccessException iae) {
158 System.err.println("newInstance failed: " + iae);
159 return;
160 } catch (LinkageError le) {
161 System.out.println("Got expected LinkageError on DE");
162 return;
163 }
164
165 /* use the base class reference to get a CL-specific instance */
166 Base baseRef = (Base) obj;
167 DoubledExtend de = baseRef.getExtended();
168
169 /* try to call through it */
170 try {
171 String result;
172
173 result = Base.doStuff(de);
174 System.err.println("ERROR: did not get LinkageError on DE");
175 System.err.println("(result=" + result + ")");
176 } catch (LinkageError le) {
177 System.out.println("Got expected LinkageError on DE");
178 return;
179 }
180 }
181
182 /**
183 * Test a doubled class that extends the base class, but is okay since
184 * it doesn't override the base class method.
185 */
186 static void testExtendOkay(ClassLoader loader) {
187 Class doubledExtendOkayClass;
188 Object obj;
189
190 /* get the "alternate" version of DoubledExtendOkay */
191 try {
192 doubledExtendOkayClass = loader.loadClass("DoubledExtendOkay");
193 } catch (ClassNotFoundException cnfe) {
194 System.err.println("loadClass failed: " + cnfe);
195 return;
196 }
197
198 /* instantiate */
199 try {
200 obj = doubledExtendOkayClass.newInstance();
201 } catch (InstantiationException ie) {
202 System.err.println("newInstance failed: " + ie);
203 return;
204 } catch (IllegalAccessException iae) {
205 System.err.println("newInstance failed: " + iae);
206 return;
207 } catch (LinkageError le) {
208 System.err.println("Got unexpected LinkageError on DEO");
209 le.printStackTrace();
210 return;
211 }
212
213 /* use the base class reference to get a CL-specific instance */
214 BaseOkay baseRef = (BaseOkay) obj;
215 DoubledExtendOkay de = baseRef.getExtended();
216
217 /* try to call through it */
218 try {
219 String result;
220
221 result = BaseOkay.doStuff(de);
222 System.out.println("Got DEO result " + result);
223 } catch (LinkageError le) {
224 System.err.println("Got unexpected LinkageError on DEO");
225 le.printStackTrace();
226 return;
227 }
228 }
229
230 /**
231 * Try to access a doubled class through a class that implements
232 * an interface declared in a different class.
233 */
234 static void testInterface(ClassLoader loader) {
235 Class getDoubledClass;
236 Object obj;
237
238 /* get GetDoubled from the "alternate" class loader */
239 try {
240 getDoubledClass = loader.loadClass("GetDoubled");
241 } catch (ClassNotFoundException cnfe) {
242 System.err.println("loadClass failed: " + cnfe);
243 return;
244 }
245
246 /* instantiate */
247 try {
248 obj = getDoubledClass.newInstance();
249 } catch (InstantiationException ie) {
250 System.err.println("newInstance failed: " + ie);
251 return;
252 } catch (IllegalAccessException iae) {
253 System.err.println("newInstance failed: " + iae);
254 return;
255 } catch (LinkageError le) {
256 // Dalvik bails here
257 System.out.println("Got LinkageError on GD");
258 return;
259 }
260
261 /*
262 * Cast the object to the interface, and try to use it.
263 */
264 IGetDoubled iface = (IGetDoubled) obj;
265 try {
266 /* "de" will be the wrong variety of DoubledExtendOkay */
267 DoubledExtendOkay de = iface.getDoubled();
268 // reference impl bails here
269 String str = de.getStr();
270 } catch (LinkageError le) {
271 System.out.println("Got LinkageError on GD");
272 return;
273 }
274 System.err.println("Should have failed by now on GetDoubled");
275 }
276
277 /**
278 * Throw an abstract class into the middle and see what happens.
279 */
280 static void testAbstract(ClassLoader loader) {
281 Class abstractGetClass;
282 Object obj;
283
284 /* get AbstractGet from the "alternate" loader */
285 try {
286 abstractGetClass = loader.loadClass("AbstractGet");
287 } catch (ClassNotFoundException cnfe) {
288 System.err.println("loadClass ta failed: " + cnfe);
289 return;
290 }
291
292 /* instantiate */
293 try {
294 obj = abstractGetClass.newInstance();
295 } catch (InstantiationException ie) {
296 System.err.println("newInstance failed: " + ie);
297 return;
298 } catch (IllegalAccessException iae) {
299 System.err.println("newInstance failed: " + iae);
300 return;
301 } catch (LinkageError le) {
302 System.out.println("Got LinkageError on TA");
303 return;
304 }
305
306 /* use the base class reference to get a CL-specific instance */
307 BaseOkay baseRef = (BaseOkay) obj;
308 DoubledExtendOkay de = baseRef.getExtended();
309
310 /* try to call through it */
311 try {
312 String result;
313
314 result = BaseOkay.doStuff(de);
315 } catch (LinkageError le) {
316 System.out.println("Got LinkageError on TA");
317 return;
318 }
319 System.err.println("Should have failed by now in testAbstract");
320 }
321
322 /**
323 * Test a doubled class that implements a common interface.
324 */
325 static void testImplement(ClassLoader loader) {
326 Class doubledImplementClass;
327 Object obj;
328
329 useImplement(new DoubledImplement(), true);
330
331 /* get the "alternate" version of DoubledImplement */
332 try {
333 doubledImplementClass = loader.loadClass("DoubledImplement");
334 } catch (ClassNotFoundException cnfe) {
335 System.err.println("loadClass failed: " + cnfe);
336 return;
337 }
338
339 /* instantiate */
340 try {
341 obj = doubledImplementClass.newInstance();
342 } catch (InstantiationException ie) {
343 System.err.println("newInstance failed: " + ie);
344 return;
345 } catch (IllegalAccessException iae) {
346 System.err.println("newInstance failed: " + iae);
347 return;
348 } catch (LinkageError le) {
349 System.out.println("Got LinkageError on DI (early)");
350 return;
351 }
352
353 /* if we lived this long, try to do something with it */
354 ICommon icommon = (ICommon) obj;
355 useImplement(icommon.getDoubledInstance(), false);
356 }
357
358 /**
359 * Do something with a DoubledImplement instance.
360 */
361 static void useImplement(DoubledImplement di, boolean isOne) {
362 //System.out.println("useObject: " + di.toString() + " -- "
363 // + di.getClass().getClassLoader());
364 try {
365 di.one();
366 if (!isOne) {
367 System.err.println("ERROR: did not get LinkageError on DI");
368 }
369 } catch (LinkageError le) {
370 if (!isOne) {
371 System.out.println("Got LinkageError on DI (late)");
372 } else {
373 throw le;
374 }
375 }
376 }
377
378
379 /**
380 * Test a class that implements an interface with a super-interface
381 * that refers to a doubled class.
382 */
383 static void testIfaceImplement(ClassLoader loader) {
384 Class ifaceImplClass;
385 Object obj;
386
387 /*
388 * Create an instance of IfaceImpl. We also pull in
389 * DoubledImplement2 from the other class loader; without this
390 * we don't fail in some implementations.
391 */
392 try {
393 ifaceImplClass = loader.loadClass("IfaceImpl");
394 ifaceImplClass = loader.loadClass("DoubledImplement2");
395 } catch (ClassNotFoundException cnfe) {
396 System.err.println("loadClass failed: " + cnfe);
397 return;
398 }
399
400 /* instantiate */
401 try {
402 obj = ifaceImplClass.newInstance();
403 } catch (InstantiationException ie) {
404 System.err.println("newInstance failed: " + ie);
405 return;
406 } catch (IllegalAccessException iae) {
407 System.err.println("newInstance failed: " + iae);
408 return;
409 } catch (LinkageError le) {
410 System.out.println("Got LinkageError on IDI (early)");
411 //System.out.println(le);
412 return;
413 }
414
415 /*
416 * Without the pre-load of FancyLoader->DoubledImplement2, some
417 * implementations will happily execute through this part. "obj"
418 * comes from FancyLoader, but the di2 returned from ifaceSuper
419 * comes from the application class loader.
420 */
421 IfaceSuper ifaceSuper = (IfaceSuper) obj;
422 DoubledImplement2 di2 = ifaceSuper.getDoubledInstance2();
423 di2.one();
424 }
425}