Type casting to a class known only at runtime?

after some strange queies to google and sun search i belive i have found my answer…

In the article:

http://java.sun.com/j2se/1.3/docs/guide/security/spec/security-spec.doc5.html

it is said that this is the order of determing which class loader is used:

-When loading the first class of an application, a new instance of the URLClassLoader is used.
-When loading the first class of an applet, a new instance of the AppletClassLoader is used.
-When java.lang.Class.ForName is directly called, the primordial class loader is used.
-If the request to load a class is triggered by a reference to it from an existing class, the class loader for the existing class is asked to load the class.

I believe the last point applies to me… am i correct in thinking that the existing class is the class i have just loaded via my custom classloader? If so then all the classes referenced in the loaded class will be asked to be loaded firstly by my custom classlader. Which is exactly what i want and so i will be able to include code in my custom class loader to load these referenced classes. Infact i think that little code will need to be added.

I will now try and implement a simple case to test this.

yes, I think you have it figured correctly. Let us know how it goes.

[quote]I believe the last point applies to me… am i correct in thinking that the existing class is the class i have just loaded via my custom classloader? If so then all the classes referenced in the loaded class will be asked to be loaded firstly by my custom classlader. Which is exactly what i want and so i will be able to include code in my custom class loader to load these referenced classes. Infact i think that little code will need to be added.
[/quote]
I’m not entirely compos mentis right now, but I’m pretty sure you’ve got that right.

The point is that when you load a funky class from an external resource (via a custom classloader), you - the java programmer - only have to load that one class, and the JVM will automatically discover and deal with every class reference / object instantiation / typecast / etc generated by that class and assume that they all live in the same place (i.e. classloader) as the original.

This is the correct assumption for all complex cases, and all non-complex cases are automatically and trivially solved by the fact that classloaders have to delegate to their parent classloader already.

Good news!

I seem to have correctly interpreted/dechiphered the paper i linked to earlier!

My test program worked exactly how i expected it to!

Program logic as follows:

Tester creates an instance of TestClassLoader.
Tester attempts to load the class Foo.

TestClassLoader looks to see whether parent classloaders are able find/load the class Foo and fails causing the method findClass(…) fomr TestClassLoader to be called.
TestClassLoader.findClass(…) attempts to load the class from a directory not in the class path (in this case “test” is used) and is successful and so creates a class from the Foo.class file located in the test directory.

Internally Foo makes use of a class called Bar which is likewise unknown to the default classloader and so the classloader who loaded the Foo instance (i.e. the TestClassLoader instance) is called to find the Bar class.

As with the Foo class, it eventually is found in the “test” directory. (This is the part which i was unsure about)

And now all the classes are loaded the program can run correctly. Yay!

Test program below:



public class Foo implements TestInterface
{
      public Foo()
      {
            System.out.println("new Foo Instance");
      }
      public Object[] process (Object[] obj)
      {
            Bar bar = new Bar();
            bar.displayMessage();
            return null;
      }

}


public class Bar 
{
      public Bar()
      {
            System.out.println("new Bar Instance");
      }
      public void displayMessage()
      {
            System.out.println("It worked! hazzah!");
      }


}


public interface TestInterface 
{
      public Object[] process(Object[] obj);

}


public class Tester {

      public static void main(String[] args) throws Exception 
      {
            ClassLoader testClassLoader =new TestClassLoader();
            Class FooClass= testClassLoader.loadClass("Foo");
            TestInterface foo = (TestInterface) FooClass.newInstance();
            Object[] results = foo.process(new Object[0]);  
      }
}


public class TestClassLoader extends ClassLoader
{


      public Class findClass(String name) 
      {
            byte[] b = loadClassData(name);
            return defineClass(name, b, 0, b.length);
      }
            
      private byte[] loadClassData(String name) 
      {
            byte[] b=null;
            try
            {
                  File file=new File("test\\"+name+".class");
                  FileInputStream fis=new FileInputStream (file);
                  b = new byte[(int)file.length()];
                  int read=fis.read(b);
                  if (read!=file.length()) throw new Exception("Bytes read not equal to the expected amount");
            }
            catch (Exception e)
            {
                  e.printStackTrace();
                  System.exit(1);
            }
            return b;
      }

}