Custom class loader in run time


In some weird cases you might need a custom class loader in run time. Probably you are right now wondering why could anyone need something like that. In my case it was all because of a bad design which could not be modified, in other cases could be something different. Anyway, if you are in the situation where a custom class loader is needed or just because you want it, here I am going to try to explain how can you create a new class loader whithout using any trick.

Around the Internet you can find some "recipes" treating this issue, but the most of them make an intensive use of Java reflection. So if you use those ways to create your custom class loader you are going to write many useless lines just trying to make your code as safe as posible because of the exceptions thrown by the reflection methods and besides it does not seem the right way. Indeed, there is a better implementation based on the URLClassLoader Java class.

First of all we need our URLClassLoader implementation:

public class MyClassLoader extends URLClassLoader {

    public MyClassLoader(ClassLoader parent)
    {
    	super(new URL[]{ },parent);
    }

    
    public void addFiles(String classPath) throws MalformedURLException
    {
        if (classPath == null)
            return;
            
        StringTokenizer tokenizer= new StringTokenizer(classPath, ",;");
        while (tokenizer.hasMoreTokens())
        {
        	File file = new File(tokenizer.nextToken());
        	if (file.exists()) {
        		addURL(file.toURI().toURL());
        	}
        }
    }
    
    
    public void addDirectories(String lib) throws MalformedURLException
    {
    	 StringTokenizer tokenizer= new StringTokenizer(lib, ",;");
         while (tokenizer.hasMoreTokens())
         {
        	 File file = new File(tokenizer.nextToken());
        	 File[] files=file.listFiles();
        	 
        	 for (File aux : files)
        	 {
     		    this.addClassPath(aux.getAbsoluteFile().getPath());
     		}
         }
    }
}

That class may be used in this way:


import de.test.CustomClassLoader;
import de.test.MyClassLoader;

public class Test {
    private CustomClassLoader test;
    
    public void createAndInitClassLoader() {
        ClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();
        MyClassLoader customClassLoader = new MyClassLoader(parentClassLoader);
        String files = new String("/usr/local/mydirectory, /usr/local/myfile.jar")
        String directoriesWithJars = new String("/usr/local/directoryWithJars");
        try {
            customClassLoader.addFiles(files);
            customClassLoader.addDirectories(directoriesWithJars);
        } catch (MalformedURLException e) {
            System.out.println("Exception while creating the custom class loader");
        }
        Thread.currentThread().setContextClassLoader(customClassLoader);

        Class serviceClass = null;
        Constructor ctor = null;
        try {
            serviceClass = Class.forName("de.test.RunInCustomClassLoader", true, customClassLoader);
            //RunInCustomClassLoader was in a jar file in /usr/local/directoryWithJars which was not loaded while launching the java virtual machine.
            Class[] params = new Class[0];
            ctor = serviceClass.getConstructor(params);
            test = (CustomClassLoader)ctor.newInstance((Object[])params);
        } catch (Exception e) {
            System.out.println("Exception while creating an instance.");
        }

        test.runInCustomClassLoader();
    }
}

Just is left the RunInCustomClassLoader class implementation. It could be something like this:

public class RunInCustomClassLoader implements CustomClassLoader {

    @Override
    public void runInCustomClassLoader() {
        System.out.println("I am running in the new class loader");
    }
}

Basically we create a new child class loader and its parent class loader is the current one. Then we set this new class loader as the class loader for the current thread.
Finally we jump onto the new class loader and it is done.

Get Lucky!!!