1

When migrated from Java 8 to Java 11, got the following error:

Caused by: java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader 'bootstrap')

Code that thrown error:

URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
...
//URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
...
getMethod().invoke(urlClassLoader, new Object[] { url });

The above error fixed when loaded jars by creating a ClassLoader as per this link: Java 9, compatability issue with ClassLoader.getSystemClassLoader

Here is the code:

public class DynamicClassLoader extends URLClassLoader {

public DynamicClassLoader(URL[] urls, ClassLoader parent) {
    super(urls, parent);
}

public void addURL(URL url) {
    super.addURL(url);
}

public DynamicClassLoader(String name, ClassLoader parent) {
    super(name, new URL[0], parent);
}

/*
 * Required when this classloader is used as the system classloader
 */
public DynamicClassLoader(ClassLoader parent) {
    this("classpath", parent);
}

public DynamicClassLoader() {
    this(Thread.currentThread().getContextClassLoader());
}

public static DynamicClassLoader findAncestor(ClassLoader cl) {
    do {

        if (cl instanceof DynamicClassLoader)
            return (DynamicClassLoader) cl;

        cl = cl.getParent();
    } while (cl != null);

    return null;
}

/*
 *  Required for Java Agents when this classloader is used as the system classloader
 */
@SuppressWarnings("unused")
private void appendToClassPathForInstrumentation(String jarfile) throws IOException {
    addURL(Paths.get(jarfile).toRealPath().toUri().toURL());
}

}

Loaded the jars using:

urlClassLoader.addURL(url);

Run the jar with

-Djava.system.class.loader=com.ltchie.util.DynamicClassLoader 

But the utility jar (jpf.jar - Java plugin framework) added at compile time unable to find the class in dynamically loaded jar at runtime and got ClassNotFoundException. Code:

Plugin plugin = pluginManager.getPlugin(pluginDescriptor.getId());

Error:

15:25:54,015 INFO  [AppApplication] >>>>>>>> loadLibraries() - ClassLoader: com.app.util.DynamicClassLoader@2f67b837  ... 
    
java.lang.NoClassDefFoundError: org/app/plugin/AppCommandPlugin
    at java.base/java.lang.ClassLoader.defineClass1(Native Method) 
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016) 
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174) 
    at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:550) 
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:458) 
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:452) 
    at java.base/java.security.AccessController.doPrivileged(Native Method) 
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:451) 
    at org.java.plugin.standard.StandardPluginClassLoader.loadLocalClass(StandardPluginClassLoader.java:395) 
    at org.java.plugin.standard.StandardPluginClassLoader.loadPluginClass(StandardPluginClassLoader.java:464) 
    at org.java.plugin.standard.StandardPluginClassLoader.loadClass(StandardPluginClassLoader.java:372) 
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521) 
    at org.java.plugin.standard.StandardPluginLifecycleHandler.createPluginInstance(StandardPluginLifecycleHandler.java:113) 
    at org.java.plugin.standard.StandardPluginManager.activatePlugin(StandardPluginManager.java:402) 
    at org.java.plugin.standard.StandardPluginManager.getPlugin(StandardPluginManager.java:217) 
    at org.app.command.AppApplication.getPlugin(AppApplication.java:253) 
    at org.app.command.AppApplication.execute(AppApplication.java:228) 
    at org.app.command.AppApplication.execute(AppApplication.java:221) 
    at org.app.command.AppApplication.startApplication(AppApplication.java:113) 
    at org.java.plugin.boot.Boot.boot(Boot.java:346) 
    at org.java.plugin.boot.Boot.main(Boot.java:243) 
    at org.app.plugin.boot.TPFBoot.main(TPFBoot.java:112)
 Caused by: java.lang.ClassNotFoundException: org.app.plugin.AppCommandPlugin 
    at org.java.plugin.standard.StandardPluginClassLoader.loadClass(StandardPluginClassLoader.java:378) 
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    ... 22 more

When I add this jar in the manifest of my jar, it works. But I need to load at runtime since this java command line application is based on JPF and there are a lot of jars we need to load when we run the application jar which uses JPF.

While checking further, noticed that pluginManager class is with another class loader:

16:57:14,000 INFO  [AppApplication] ############ pluginManager.getPlugin: jdk.internal.loader.ClassLoaders$AppClassLoader@799f7e29

This pluginManager instance is from the parent class available in jpf.jar which is defined in the compile-time jar dependency of my application jar manifest. So my application is running with class loader DynamicClassLoader and loads run time jars into that. But the dependency jar added in the manifest is using the default AppClassLoader which causes this unable to find my class.

Anyone, please suggest a solution.

Holger
  • 285,553
  • 42
  • 434
  • 765
Valsaraj Viswanathan
  • 1,473
  • 5
  • 28
  • 51
  • 3
    *Anyone please suggest a solution.* - Create a new `URLClassLoader` for the new JAR url. (See the duplink!!) If that doesn't work, show us your attempt at creating / using a new classloader so that we can see what is going wrong. And include the full (new) stacktrace. – Stephen C Sep 17 '21 at 10:00
  • I have created URLClassLoader child class as per the dupe link but not worked in my application. Updated the question with scenario, error details and code. – Valsaraj Viswanathan Sep 17 '21 at 11:09
  • @ValsarajViswanathan Please check if this works. I am not sure if it serves your purpose. ClassLoader classloader = SecureClassLoader.getSystemClassLoader(); URLClassLoader urlClassLoader = URLClassLoader.newInstance(urls, classloader); Thread.currentThread().setContextClassLoader(urlClassLoader); – Kishor Raskar Sep 17 '21 at 16:53
  • 2
    I think, this approach won’t work in general. I [added a comment](https://stackoverflow.com/questions/60764/how-to-load-jar-files-dynamically-at-runtime#comment123909471_59743937) at the original post. – Holger Nov 24 '21 at 11:52

0 Answers0