Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
603 views
in Technique[技术] by (71.8m points)

Java 11 issue with adding dependency jars at runtime

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...