Sunil Kumar
Sunil Kumar

Reputation: 5657

How to add / load a class to Extension class loader at runtime?

In my project(at runtime) : Application class loader is loaded with some set of classes.And I have a user class loader, loaded with some set of classes.

Now there is a class in application class loader which is trying to load a class that is not there in application class loader,but exist in the user class loader.

Eg : a class in Application class loader having code like

this.getClass().getClassLoader().loadClass("user class").

Note : I don't have access to class(which is in application class loader) and I can cant add class to load to application class loader.

How to load such class ?

This scenario happens in Drivermanager class :

I have DriverManager in Application Class Loader and Driver class in User class loader. And DriverManager tries to load driver class in Application class loader and it fails to load class.

So I want to add driver class to application or Extension class loader at runtime.But how to do it ?

Upvotes: 2

Views: 5964

Answers (2)

Sunil Kumar
Sunil Kumar

Reputation: 5657

I have two solutions to go,

1) Override Driver manager class and use Thread.currentThread().getContextClassLoader() instead of this.getClass().getClassLoader() to load driver class.

2) Get System class loader instance and there is protected api in system class loader addURL(),which adds resources to system class loader at runtime.

By Using reflection,if you can invoke addURL() api then driver class will be availble to Driver Manager at system class loader. Here is the code sanppit

    URL[] urls = new URL[]{jarFile.toURL()};
    ClassLoader cl = ClassLoader.getSystemClassLoader()
    if ( cl instanceof URLClassLoader ) {
        URLClassLoader ul = (URLClassLoader) cl;

        // addURL is a protected method, but we can use reflection to call it
        Class<?>[] paraTypes = new Class[1];
        paraTypes[0] = URL.class;
        Method method = URLClassLoader.class.getDeclaredMethod("addURL", paraTypes);
        method.setAccessible(true);
        Object[] args = new Object[1];
        for (int i = 0; i < urls.length; i++) {
            args[0] = urls[i];
            method.invoke(ul, args);
        }
    }

Note : This way,you can only add resource to system class loader,but you cant unregister added resource from the class loader.Which result issues if you have versions of jars.

Upvotes: 1

gaborsch
gaborsch

Reputation: 15758

Try to use the thread classloader:

Thread.currentThread().getContextClassLoader() 

In your example:

Class<?> driverClass = Thread.currentThread().getContextClassLoader().loadClass("user class name")

I suppose these user classes will implement some interface, defined (loaded) in Application classloader, so you will treat them through this interface. In this case there should be no problem using such loaded classes.

You can instantiate an object instance from that with the default constructor (you must catch a number of Exceptions, though):

userDriver = (Driver) driverClass.newInstance();

If you want to use another constructor (e.g. with a String parameter):

Constructor<?> c = driverClass.getConstructor(String.class);
userDriver = (Driver) c.newInstance("String param to constructor");

Upvotes: 3

Related Questions