Search code examples
javajarjvmclassloaderurlclassloader

Java class loader independent from the system class loader for jar files


I'm trying to load a jar file inside a program to invoke different methods. I have a class that does the work, but the class loads the jar file using a URLClassLoader, which is dependent of the system class loader, so, for example, if the loaded jar performs a System.exit() it finishes the execution of the whole application, terminating the currently running Java Virtual Machine. My intention is that, if the loaded jar do this last, it only finishes the jar, not the entire application. Also, I want to be able to close the jar so I can restart it later, if needed. I'm using the following code to instantiate the required class from the jar and to invoke the methods from my application:

// Load a class with classloader = new URLClassLoader(libs);
if(loadclass == null)
    loadclass = Class.forName(classname, true, classloader);
// Execute method
if(met == null)
{
    Constructor constructor;
    if(params != null && params.length > 0)
    {
        constructor = loadclass.getConstructor(new Class[]{Object[].class});
        classinstance = constructor.newInstance(new Object[]{params});
    }
    else
    {
        constructor = loadclass.getConstructor(null);
        classinstance = constructor.newInstance(null);
    }
    return (Object)Boolean.TRUE;
}

// Generic instance
if(classinstance == null)
    classinstance = loadclass.newInstance();

// Method invocation
Method method;
if(params != null)
{
    if(params.length > 1)
        method = loadclass.getMethod(met, new Class[]{Object[].class});
    else
        method = loadclass.getMethod(met, new Class[]{Object.class});
}
else
    method = loadclass.getMethod(met);

method.setAccessible(true);
Object ret;
if(params != null)
{
    if(params.length > 1)
        ret = (Object)method.invoke(classinstance, new Object[]{params});
    else
        ret = (Object)method.invoke(classinstance, params[0]);
}
else
    ret = (Object)method.invoke(classinstance, null);

return ret;

I don't know how to decouple my URLClassLoader from the system class loader. Any help to this point is appreciated!


Solution

  • System.exit() will exit the process regardless of the Class Loader. Abandoning the system class loader can be done by not chaining the class loaders, however be warned. This means that all system classes will need to be loaded afreash, and they will not play nicely together. For example, comparing a string created by one class loader with another string containing the same characters from a different class loader would fail.

    To prevent calls to System.exit() from succeeding, then the security manager could be configured to error.

    Here is the code for System.exit()

    public void exit(int status) {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkExit(status);
        }
        Shutdown.exit(status);
    }
    

    it calls security.checkExit on the security manager. Which in turn is implemented as thus:

    public void checkExit(int status) {
        checkPermission(new RuntimePermission("exitVM."+status));
    }
    

    Notice the use of the permissions exitVM.<number>. Further detail on the security manager, and installing one can be read here.