Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4303167

ClassLoader mechanism doesn't work as specified with inheritance

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 1.3.0
    • core-libs
    • x86
    • windows_nt

      Latest Information:

      From: "Mark Claassen" <###@###.###>
      To: "chamness" <###@###.###>
      Subject: RE: (Review ID: 99102) ClassLoader mechanism doesn't work as specified with inheritance
      Date: Fri, 7 Jan 2000 17:00:19 -0500

      Hi. I wrote this bug a while ago, and I was able to work around it. It may
      still be a bug, but it is not the bug I thought it was.

      What I found was that since the class file was accessible to the primordial
      class loader it was not actually using the loader specified in
      loader.loadClass(""). This is as it is supposed to be, I think. I read
      somewhere that the primordial loader always get first crack at loading a
      class.

      So, what I think is happening is this:
      myLoader.loadClass("MyClass")
      --
      myLoader hands the task first to the pLoader
      pLoader finds MyClass and loads it. MyClass knows it was loaded by the
      primordial loader.
      myLoader sees that the class is loaded.
      Done.
      --
      instantiate the MyClass
      --
      Get the MyClass's ClassLoader => This is not MyLoader, but the primordial
      loader!
      Look at declaration:
      extends Object, pLoader => I can load that!
      InterfaceA, pLoader => I know nothing about this!
      InterfaceB, pLoader => I know nothing about this!

      Move MyClass to a place where the primordial loader can't find it and it
      works.

      So now a question remains, should the original class be registered to the
      primordial loader or the custom loader? I could make an argument either
      way.

      If it would be registered to myLoader, every class loaded by this
      ClassLoader that could be loaded by the primordial loader would be, thereby
      negating any security issues. If you would create several ClassLoaders, one
      being built on top of another, then any class loaded by the top one could
      reflect any of the class loaders created so far created. This could be
      confusing. (As it was for me.)

      Implementation of the other way might be difficult. I have not tried to
      find out how a class knows what loaded it, but I can see changing this might
      now be easy.

      Regardless, this is subtle and it might be helpful if a short comment in the
      docs was made to reflect this.

      =====================================
      Name: mc57594 Date: 01/06/2000

      java version "1.3.0"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-I)
      Java HotSpot(TM) Client VM (build 1.3-I, mixed mode)


        From what I have read (and by demonstration) subclassing the class loader for
      a Java Application will cause the new ClassLoader to be used when looking for
      classes. This seems to be the case, except in this example. The source files
      are included at the end. The problem is with inheritance.

      First, the setup:
      LoaderApplication has a public static void main(String[]) method. It then
      subclasses the ClassLoader. The reason for this is to add some additional jar
      files to the classpath.

      The TestPanel is the class that will be instantiated by first loading the class
      from the custom class loader and then creating a new instance of it. This
      class implements two interfaces ("InterfaceA" and "InterfaceB") each in their
      own separate packages and jar files ("InterfaceA" in package "dsi" and jar
      file "dsi.jar". "InterfaceB in package "dsix" and jar file "dsix.jar" Both
      of these interfaces are empty stubs defining no variables or methods.

      jar -tvf dsi.jar
           0 Thu Dec 16 11:21:48 EST 1999 META-INF/
          68 Thu Dec 16 11:21:48 EST 1999 META-INF/MANIFEST.MF
           0 Thu Dec 16 11:00:42 EST 1999 dsi/
         105 Thu Dec 16 11:00:42 EST 1999 dsi/InterfaceA.class

      jar -tvf dsix.jar
           0 Thu Dec 16 11:24:02 EST 1999 META-INF/
          68 Thu Dec 16 11:24:02 EST 1999 META-INF/MANIFEST.MF
           0 Thu Dec 16 11:00:42 EST 1999 dsix/
         106 Thu Dec 16 11:00:42 EST 1999 dsix/InterfaceB.class


      I am using NT, so I am running this from a file called RUNNIT.BAT:

      ---FILE---
      set CLASSPATH=.
      rem set CLASSPATH=%CLASSPATH%;dsi.jar
      rem set CLASSPATH=%CLASSPATH%;dsix.jar

      java LoaderApplication
      ---
      By uncommenting the classpath lines for the jar files everything works,
      although not with the correct class loader. Commenting them out should not
      make a difference since these are added to the path in the new class loader.

      Running the program with the jar commented out, I get the following. Please
      note a few things:
      1) InterfaceA and InterfaceB are available to the new class loader.
      2) dsi.interfaceA and dsix/interfaceB are both loaded, regardless of the
      syntactic difference
      3) TestPanel and an instance of Object are both loaded from the new ClassLoader
      4) The interfaces are not loaded by the new class loader and are therefore not
      found.
      5) JPanel, ancestor of TestPanel is either not loading by the new loader or is
      not loading yet.


      Primordial
      file:/D:/dsi/BugTests/Loader/
      getURLs
      file:/D:/dsi/BugTests/Loader/dsi.jar
      file:/D:/dsi/BugTests/Loader/dsix.jar
      loadClass: dsi.InterfaceA
      findClass: dsi.InterfaceA
      loadClass: java.lang.Object
      loadClass: dsix/InterfaceB
      findClass: dsix/InterfaceB
      loadClass: TestPanel
      Not finding TestPanel
      Exception in thread "main" java.lang.NoClassDefFoundError: dsi/InterfaceA
              at java.lang.ClassLoader.defineClass0(Native Method)
              at java.lang.ClassLoader.defineClass(ClassLoader.java:453)
              at java.security.SecureClassLoader.defineClass
      (SecureClassLoader.java:106)
              at java.net.URLClassLoader.defineClass(URLClassLoader.java:251)
              at java.net.URLClassLoader.access$100(URLClassLoader.java:59)
              at java.net.URLClassLoader$1.run(URLClassLoader.java:198)
              at java.security.AccessController.doPrivileged(Native Method)
              at java.net.URLClassLoader.findClass(URLClassLoader.java:191)
              at java.lang.ClassLoader.loadClass(ClassLoader.java:291)
              at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:290)
              at java.lang.ClassLoader.loadClass(ClassLoader.java:284)
              at LoaderApplication$1.loadClass(LoaderApplication.java:67)
              at LoaderApplication.<init>(LoaderApplication.java:83)
              at LoaderApplication.main(LoaderApplication.java:21)

      Detailed articles on the class loader seem to be far and few between, even on
      your site, so I am kind of shooting from hip here. However, it does seem to
      allude that this functionality is possible. Unfortunately, most articles give
      trivial examples where the inheritance only comes from class that can be loaded
      from the primordial class loader.

      I hope not to waste your time with an error on my part, but from what I have
      read, this is a valid way to do this and it is not working.

      Thank you for your time,
      Mark


      ---FILE---
      import java.net.URL;
      import java.net.URLConnection;
      import java.net.MalformedURLException;
      import java.net.URLClassLoader;

      import java.lang.reflect.Method;
      import java.lang.reflect.Constructor;
      import java.awt.event.WindowEvent;
      import java.awt.event.WindowAdapter;

      import java.io.File;

      import javax.swing.JFrame;
      import javax.swing.JPanel;

      public final class LoaderApplication extends JFrame {
      public static void main(String argv[]) {
      LoaderApplication app = new LoaderApplication(argv);
      }
      public LoaderApplication(String[] argv) {
      super("Class Loader Test");
      //ploader us the Primordial ClassLoader,
      //loader will be the new one.
      URLClassLoader loader, ploader;
      ploader = (URLClassLoader) ClassLoader.getSystemClassLoader();
      try {
      //Make sure we have a valid URL for the jar files.
      String s;
      File f = new File(".");
      s = "file:/" + f.getAbsolutePath();
      int index = s.lastIndexOf(File.separator);
      s = s.substring(0,index+1);

      URL[] urls;
      urls = ploader.getURLs();
      //See what is in the primordial loader
      System.out.println("Primordial");
      for (int i = 0; i < urls.length; i++)
      System.out.println(urls[i]);

      urls = new URL[2];
      urls[0] = new URL(s+"dsi.jar");

      urls[1] = new URL(s+"dsix.jar");

      //Create new class loader
      loader = new URLClassLoader(urls,ploader) {
      protected Class findClass(String name) throws
      ClassNotFoundException {
      System.out.println("findClass: " +
      name);
      return super.findClass(name);
      }
      public URL findResource(String name) {
      System.out.println("findResource: " +
      name);
      return super.findResource(name);
      }
      public java.util.Enumeration findResources
      (String name) throws java.io.IOException {
      System.out.println("findResources: " +
      name);
      return super.findResources(name);
      }
      public URL[] getURLs() {
      System.out.println("getURLs");
      return super.getURLs();
      }
      public Class loadClass(String name) throws
      ClassNotFoundException {
      System.out.println("loadClass: " +
      name);
      Class c = null;
      try {
      c = super.loadClass(name,true);
      }
      catch (NoClassDefFoundError e) {
      System.out.println("Not
      finding " + name);
      throw e;
      }
      return c;
      }
      };
      urls = loader.getURLs();
      for (int i = 0; i < urls.length; i++)
      System.out.println(urls[i]);

      Class testClass;
      //Test new ClassLoader
      testClass = loader.loadClass("dsi.InterfaceA");
      //Test new ClassLoader
      testClass = loader.loadClass("dsix/InterfaceB");
      testClass = loader.loadClass("TestPanel");
      Constructor[] constructors =
      testClass.getDeclaredConstructors();
      int number;
      for (number = 0; number < constructors.length;
      number++) {
      Class[] types = constructors
      [number].getParameterTypes();
      if (types.length == 1 && types[0] == String
      [].class) {
      //This is going to be there, so I am
      guarenteed to find it.
      break;
      }
      }
      Object[] params = new Object[1];
      params[0] = argv;
      Object testPanel = constructors[number].newInstance
      (params);
      getContentPane().add( (JPanel)testPanel);
      //Call my run method. My production class does not
      implement runnable.
      Method m = testClass.getMethod("run",null);
      m.invoke(testPanel,null);
      pack();
      setSize(200,100);
      addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
      System.exit(0);
      }
      });
      show();


      }
      catch (MalformedURLException e) {
      System.out.println("Unable to initialize Module
      Loader.");
      }
      catch (Exception e) {
      System.out.println(e.getClass());
      System.out.println(e.getMessage());
      e.printStackTrace();
      System.out.println("Unable to initialize Module
      Loader.");
      }
      }
      }
      ---FILE---
      import dsi.InterfaceA;
      import dsix.InterfaceB;

      import javax.swing.JPanel;
      import javax.swing.JLabel;

      public class TestPanel extends JPanel implements InterfaceA, InterfaceB {

      public TestPanel(String[] argv) {

      }
      public void run() {
      add(new JLabel("Lucky Day is my hero!"));
      }
      }
      ---FILE---
      package dsi;

      public interface InterfaceA {
      }
      ---FILE---
      package dsix;

      public interface InterfaceB {
      }
      (Review ID: 99102)
      ======================================================================

            zlisunw Zhenghua Li (Inactive)
            mchamnessunw Mark Chamness (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: