开发者

Java - Custom ClassLoader - trying to load a class using class file full path

As part of an HTTP WebServer project for academic purposes, I'm trying write my own custom class loader for web application classes, but can't seem to get it right.

Generally speaking, web applications are located in their own folders, the ".class" file of the web application is the same as it's direct parent folder name. (e.g. Web1/Web1.class). The below code works fine until I reach the defineClass() method, and then it throws me out with the following exception:

java.io.FileNotFoundException: C:\inetpub\javawwwroot\WebApps\java\lang\Object\.Object.class (The system cannot find the path specified)

It's well worth to mention that the C:\inetpub\javawwwroot\WebApps\ part equals m_WebAppsFullPath variable in the code below.

Also, when trying to use

InputStream in = getResourceAsStream(clsFile);

instead of InputStream in = new FileInputStream(clsFile);

I get a null return value...

UPDATE: In short, how can I load a specific class which isn't located in the "CLASSPATH" nor located in any of the packages of my project?

protected synchronized Class loadClass(String className, boolean resolve) 
                             throws ClassNotFoundException 
{
    log("Loading class: " + className + ", resolve: " + resolve);

    // 1. is this class already loaded?
    Class cls = findLoadedClass(className);
    if (cls != null)
    {
        return cls;
    }

    // 2. get class file name from class name
    String classRelativePath = className.replace('.', '/');
    String classFileName = 
        ((className.lastIndexOf('.') != -1) ? className.substring(className.lastIndexOf('.')) : className) + ".class";

    String clsFile = m_WebAppsFullPath + "\\" + classRelativePath + "\\" + classFileName;

    // 3. get bytes for class
    byte[] classBytes = null;
    try 
    {
        //InputStream in = getResourceAsStream(clsFile);
        InputStream in = new FileInputStream(clsFile);
        byte[] buffer = new byte[BUFFER_SIZE];
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int n = -1;
        while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
            out.write(buffer, 0, n);
        }
        classBytes = out.toByteArray();
    }
    catch (IOException e) {
        log("ERROR loading class file: " + e);
    }

    if (classBytes == null) {
        throw new ClassNotFoundException("Can开发者_StackOverflownot load class: " + className);
    }

    // 4. turn the byte array into a Class
    try {
        cls = defineClass(className, classBytes, 0, classBytes.length);
        if (resolve) {
            resolveClass(cls);
        }
    }
    catch (SecurityException e) { 
        // loading core java classes such as java.lang.String
        // is prohibited, throws java.lang.SecurityException.
        // delegate to parent if not allowed to load class
        cls = super.loadClass(className, resolve);
    }

    return cls;
}

Any idea how can I get it to work?

Thanks!


At the moment, you're not only trying to load your custom classes via your own class loader, but all the sytem clases they depend on as well. Like e.g. java.lang.Object, which is your Problem here.

Generally, classloaders in Java are chained, which means, that your classloader has been defined by another one (most likely the system classloader). Therefore, it is advisable, to NOT overwrite the loadClass method yourself, but instead overwrite the two methods 'findClass(String):Class and loadClassData(String):Class.

Here is an excerp from the Javadoc of the Classloader class:

The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance.

The same Javadoc even lists an example, how to define a custom classloader properly:

class NetworkClassLoader extends ClassLoader {
     String host;
     int port;

     public Class findClass(String name) {
         byte[] b = loadClassData(name);
         return defineClass(name, b, 0, b.length);
     }

     private byte[] loadClassData(String name) {
         // load the class data from the connection
          . . .
     }
 }

I think you might want to read that: Javadoc for ClassLoader

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜