Java custom class loader example 

Joined:
04/09/2007
Posts:
770

February 09, 2009 23:14:15    Last update: February 09, 2009 23:14:15
This example demonstrates the general steps in creating a custom Java class loader. Normally a class loader would consult its parent class loader when asked to load a class. If it's not loaded by the parent class loader, then the class loader would try to load the class on its own.

This class loader tries to load the requested class on its own first, and delegates to the parent only when a java.lang.SecurityException is thrown (which happens when it tries to load core Java classes such as java.lang.String). The classes are loaded from CLASSPATH through the getResourceAsStream call.

It's important to note that when a class is loaded with a certain class loader, all classes referenced from that class are also loaded through the same class loader (unless another class loader is specifically requested).

package demo;

import java.io.*;

public class MyClassLoader extends ClassLoader {
    private static final int BUFFER_SIZE = 8192;

    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 clsFile = className.replace('.', '/') + ".class";
        
        // 3. get bytes for class
        byte[] classBytes = null;
        try {
            InputStream in = getResourceAsStream(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("Cannot 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;
    }

    private static void log(String s) {
        System.out.println(s);
    }
}


Test code:
package demo;

public class TestClassLoader {
    public static void main(String[] args) throws Exception {
        MyClassLoader loader1 = new MyClassLoader();
        
        // load demo.Base64
        Class clsB64 = Class.forName("demo.Base64", true, loader1);
        System.out.println("Base64 class: " + clsB64);

        if (Base64.class.equals(clsB64)) {
            System.out.println("Base64 loaded through custom loader is the same as that loaded by System loader.");
        }
        else {
            System.out.println("Base64 loaded through custom loader is NOT same as that loaded by System loader.");
        }

        // call the main method in Base64
        java.lang.reflect.Method main = clsB64.getMethod("main", 
                                                new Class[] {String[].class});
        main.invoke(null, new Object[]{ new String[]{} });
    }
}


where I used the public domain Base64 code for the test.

Share |
| Comment  | Tags