diff options
Diffstat (limited to 'tests/068-classloader/src/Main.java')
-rw-r--r-- | tests/068-classloader/src/Main.java | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/tests/068-classloader/src/Main.java b/tests/068-classloader/src/Main.java new file mode 100644 index 0000000..1bc7b04 --- /dev/null +++ b/tests/068-classloader/src/Main.java @@ -0,0 +1,425 @@ +/* + * 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. + */ + +/** + * Class loader test. + */ +public class Main { + /** + * Main entry point. + */ + public static void main(String[] args) { + FancyLoader loader; + + loader = new FancyLoader(ClassLoader.getSystemClassLoader()); + //System.out.println("SYSTEM: " + ClassLoader.getSystemClassLoader()); + //System.out.println("ALTERN: " + loader); + + /* + * This statement has no effect on this program, but it can + * change the point where a LinkageException is thrown in + * testImplement(). When this is present the "reference + * implementation" throws an exception from Class.newInstance(), + * when it's absent the exception is deferred until the first time + * we call a method that isn't actually implemented. + * + * This isn't the class that fails -- it's a class with the same + * name in the "fancy" class loader -- but the VM thinks it has a + * reference to one of these; presumably the difference is that + * without this the VM finds itself holding a reference to an + * instance of an uninitialized class. + */ + System.out.println("base: " + DoubledImplement.class); + System.out.println("base2: " + DoubledImplement2.class); + + /* + * Run tests. + */ + testAccess1(loader); + testAccess2(loader); + testAccess3(loader); + + testExtend(loader); + testExtendOkay(loader); + testInterface(loader); + testAbstract(loader); + testImplement(loader); + testIfaceImplement(loader); + } + + /** + * See if we can load a class that isn't public to us. We should be + * able to load it but not instantiate it. + */ + static void testAccess1(ClassLoader loader) { + Class altClass; + + try { + altClass = loader.loadClass("Inaccessible1"); + } catch (ClassNotFoundException cnfe) { + System.err.println("loadClass failed"); + cnfe.printStackTrace(); + return; + } + + /* instantiate */ + Object obj; + try { + obj = altClass.newInstance(); + System.err.println("ERROR: Inaccessible1 was accessible"); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.out.println("Got expected access exception #1"); + //System.out.println("+++ " + iae); + return; + } + } + + /** + * See if we can load a class whose base class is not accessible to it + * (though the base *is* accessible to us). + */ + static void testAccess2(ClassLoader loader) { + Class altClass; + + try { + altClass = loader.loadClass("Inaccessible2"); + System.err.println("ERROR: Inaccessible2 was accessible"); + } catch (ClassNotFoundException cnfe) { + Throwable cause = cnfe.getCause(); + if (cause instanceof IllegalAccessError) { + System.out.println("Got expected CNFE/IAE #2"); + } else { + System.err.println("Got unexpected CNFE/IAE #2"); + cnfe.printStackTrace(); + } + } + } + + /** + * See if we can load a class with an inaccessible interface. + */ + static void testAccess3(ClassLoader loader) { + Class altClass; + + try { + altClass = loader.loadClass("Inaccessible3"); + System.err.println("ERROR: Inaccessible3 was accessible"); + } catch (ClassNotFoundException cnfe) { + Throwable cause = cnfe.getCause(); + if (cause instanceof IllegalAccessError) { + System.out.println("Got expected CNFE/IAE #3"); + } else { + System.err.println("Got unexpected CNFE/IAE #3"); + cnfe.printStackTrace(); + } + } + } + + /** + * Test a doubled class that extends the base class. + */ + static void testExtend(ClassLoader loader) { + Class doubledExtendClass; + Object obj; + + /* get the "alternate" version of DoubledExtend */ + try { + doubledExtendClass = loader.loadClass("DoubledExtend"); + //System.out.println("+++ DoubledExtend is " + doubledExtendClass + // + " in " + doubledExtendClass.getClassLoader()); + } catch (ClassNotFoundException cnfe) { + System.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = doubledExtendClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.println("newInstance failed: " + iae); + return; + } catch (LinkageError le) { + System.out.println("Got expected LinkageError on DE"); + return; + } + + /* use the base class reference to get a CL-specific instance */ + Base baseRef = (Base) obj; + DoubledExtend de = baseRef.getExtended(); + + /* try to call through it */ + try { + String result; + + result = Base.doStuff(de); + System.err.println("ERROR: did not get LinkageError on DE"); + System.err.println("(result=" + result + ")"); + } catch (LinkageError le) { + System.out.println("Got expected LinkageError on DE"); + return; + } + } + + /** + * Test a doubled class that extends the base class, but is okay since + * it doesn't override the base class method. + */ + static void testExtendOkay(ClassLoader loader) { + Class doubledExtendOkayClass; + Object obj; + + /* get the "alternate" version of DoubledExtendOkay */ + try { + doubledExtendOkayClass = loader.loadClass("DoubledExtendOkay"); + } catch (ClassNotFoundException cnfe) { + System.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = doubledExtendOkayClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.println("newInstance failed: " + iae); + return; + } catch (LinkageError le) { + System.err.println("Got unexpected LinkageError on DEO"); + le.printStackTrace(); + return; + } + + /* use the base class reference to get a CL-specific instance */ + BaseOkay baseRef = (BaseOkay) obj; + DoubledExtendOkay de = baseRef.getExtended(); + + /* try to call through it */ + try { + String result; + + result = BaseOkay.doStuff(de); + System.out.println("Got DEO result " + result); + } catch (LinkageError le) { + System.err.println("Got unexpected LinkageError on DEO"); + le.printStackTrace(); + return; + } + } + + /** + * Try to access a doubled class through a class that implements + * an interface declared in a different class. + */ + static void testInterface(ClassLoader loader) { + Class getDoubledClass; + Object obj; + + /* get GetDoubled from the "alternate" class loader */ + try { + getDoubledClass = loader.loadClass("GetDoubled"); + } catch (ClassNotFoundException cnfe) { + System.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = getDoubledClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.println("newInstance failed: " + iae); + return; + } catch (LinkageError le) { + // Dalvik bails here + System.out.println("Got LinkageError on GD"); + return; + } + + /* + * Cast the object to the interface, and try to use it. + */ + IGetDoubled iface = (IGetDoubled) obj; + try { + /* "de" will be the wrong variety of DoubledExtendOkay */ + DoubledExtendOkay de = iface.getDoubled(); + // reference impl bails here + String str = de.getStr(); + } catch (LinkageError le) { + System.out.println("Got LinkageError on GD"); + return; + } + System.err.println("Should have failed by now on GetDoubled"); + } + + /** + * Throw an abstract class into the middle and see what happens. + */ + static void testAbstract(ClassLoader loader) { + Class abstractGetClass; + Object obj; + + /* get AbstractGet from the "alternate" loader */ + try { + abstractGetClass = loader.loadClass("AbstractGet"); + } catch (ClassNotFoundException cnfe) { + System.err.println("loadClass ta failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = abstractGetClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.println("newInstance failed: " + iae); + return; + } catch (LinkageError le) { + System.out.println("Got LinkageError on TA"); + return; + } + + /* use the base class reference to get a CL-specific instance */ + BaseOkay baseRef = (BaseOkay) obj; + DoubledExtendOkay de = baseRef.getExtended(); + + /* try to call through it */ + try { + String result; + + result = BaseOkay.doStuff(de); + } catch (LinkageError le) { + System.out.println("Got LinkageError on TA"); + return; + } + System.err.println("Should have failed by now in testAbstract"); + } + + /** + * Test a doubled class that implements a common interface. + */ + static void testImplement(ClassLoader loader) { + Class doubledImplementClass; + Object obj; + + useImplement(new DoubledImplement(), true); + + /* get the "alternate" version of DoubledImplement */ + try { + doubledImplementClass = loader.loadClass("DoubledImplement"); + } catch (ClassNotFoundException cnfe) { + System.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = doubledImplementClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.println("newInstance failed: " + iae); + return; + } catch (LinkageError le) { + System.out.println("Got LinkageError on DI (early)"); + return; + } + + /* if we lived this long, try to do something with it */ + ICommon icommon = (ICommon) obj; + useImplement(icommon.getDoubledInstance(), false); + } + + /** + * Do something with a DoubledImplement instance. + */ + static void useImplement(DoubledImplement di, boolean isOne) { + //System.out.println("useObject: " + di.toString() + " -- " + // + di.getClass().getClassLoader()); + try { + di.one(); + if (!isOne) { + System.err.println("ERROR: did not get LinkageError on DI"); + } + } catch (LinkageError le) { + if (!isOne) { + System.out.println("Got LinkageError on DI (late)"); + } else { + throw le; + } + } + } + + + /** + * Test a class that implements an interface with a super-interface + * that refers to a doubled class. + */ + static void testIfaceImplement(ClassLoader loader) { + Class ifaceImplClass; + Object obj; + + /* + * Create an instance of IfaceImpl. We also pull in + * DoubledImplement2 from the other class loader; without this + * we don't fail in some implementations. + */ + try { + ifaceImplClass = loader.loadClass("IfaceImpl"); + ifaceImplClass = loader.loadClass("DoubledImplement2"); + } catch (ClassNotFoundException cnfe) { + System.err.println("loadClass failed: " + cnfe); + return; + } + + /* instantiate */ + try { + obj = ifaceImplClass.newInstance(); + } catch (InstantiationException ie) { + System.err.println("newInstance failed: " + ie); + return; + } catch (IllegalAccessException iae) { + System.err.println("newInstance failed: " + iae); + return; + } catch (LinkageError le) { + System.out.println("Got LinkageError on IDI (early)"); + //System.out.println(le); + return; + } + + /* + * Without the pre-load of FancyLoader->DoubledImplement2, some + * implementations will happily execute through this part. "obj" + * comes from FancyLoader, but the di2 returned from ifaceSuper + * comes from the application class loader. + */ + IfaceSuper ifaceSuper = (IfaceSuper) obj; + DoubledImplement2 di2 = ifaceSuper.getDoubledInstance2(); + di2.one(); + } +} |