Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 9 - add jar dynamically at runtime

I've got a classloader problem with Java 9.

This code worked with previous Java versions:

 private static void addNewURL(URL u) throws IOException {
    final Class[] newParameters = new Class[]{URL.class};
    URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
    Class newClass = URLClassLoader.class;
    try {
      Method method = newClass.getDeclaredMethod("addNewURL", newParameters );
      method.setAccessible(true);
      method.invoke(urlClassLoader, new Object[]{u});
    } catch (Throwable t) {
      throw new IOException("Error, could not add URL to system classloader");
    }
  }

From this thread I learned that this has to be replaced by something like this:

Class.forName(classpath, true, loader);

loader = URLClassLoader.newInstance(
            new URL[]{u},
            MyClass.class.getClassLoader()

MyClass is the class I'm trying to implement the Class.forName() method in.

u = file:/C:/Users/SomeUser/Projects/MyTool/plugins/myNodes/myOwn-nodes-1.6.jar

String classpath = URLClassLoader.getSystemResource("plugins/myNodes/myOwn-nodes-1.6.jar").toString();

For some reason - I really can't figure out, why - I get a ClassNotFoundException when running Class.forName(classpath, true, loader);

Does someone know what I'm doing wrong?

like image 289
RuntimeError Avatar asked Jan 18 '18 13:01

RuntimeError


1 Answers

From the documentation of the Class.forName(String name, boolean initialize, ClassLoader loader) :-

throws ClassNotFoundException - if the class cannot be located by the specified class loader

Also, note the arguments used for the API includes the name of the class using which the classloader returns the object of the class.

Given the fully qualified name for a class or interface (in the same format returned by getName) this method attempts to locate, load, and link the class or interface.

In your sample code, this can be redressed to something like :

// Constructing a URL form the path to JAR
URL u = new URL("file:/C:/Users/SomeUser/Projects/MyTool/plugins/myNodes/myOwn-nodes-1.6.jar");

// Creating an instance of URLClassloader using the above URL and parent classloader 
ClassLoader loader = URLClassLoader.newInstance(new URL[]{u}, MyClass.class.getClassLoader());

// Returns the class object
Class<?> yourMainClass = Class.forName("MainClassOfJar", true, loader);

where MainClassOfJar in the above code shall be replaced by the main class of the JAR myOwn-nodes-1.6.jar.

like image 181
Naman Avatar answered Oct 05 '22 10:10

Naman