相关文章推荐
仗义的莲藕  ·  陈德宁 副教授·  11 月前    · 
温文尔雅的花生  ·  mysql ...·  1 年前    · 
骑白马的金针菇  ·  更新后windows ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I am trying to understand how to access/make available a jar file using URLClassLoader.

Firstly I am loading the jar file with

    package myA;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import org.jgroups.JChannel;
public class loader {
    JChannel channel;
        String user_name=System.getProperty("user.name", "n/a");
        private void start() throws Exception {
            channel=new JChannel(); // use the default config, udp.xml
            channel.connect("ChatCluster");
    public void loadMe()throws ClassNotFoundException, MalformedURLException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
        URL classUrl;
        classUrl = new URL("file:///home/myJars/jgroups-3.4.2.Final.jar");
        URL[] classUrls = { classUrl };
        URLClassLoader ucl = new URLClassLoader(classUrls);
        Class<?> c = ucl.loadClass("org.jgroups.JChannel");
        for(Field f: c.getDeclaredFields()) {
            System.out.println("Field name=" + f.getName());
        Object instance = c.newInstance();  
        //Method theMethod = c.getMethod("main");
        //theMethod.invoke(instance);
     public static void main(String[] args) throws Exception {
         new loader().loadMe();
         new  loader().start();

the printout shows the declared fields that are in jgroups-3.4.2.Final.jar, however it then throws a classnotfound error.

java -cp myA.jar myA.loader
Field name=DEFAULT_PROTOCOL_STACK
Field name=local_addr
Field name=address_generator
Field name=name
Field name=cluster_name
Field name=my_view
Field name=prot_stack
Field name=state_promise
Field name=state_transfer_supported
Field name=flush_supported
Field name=config
Field name=stats
Field name=sent_msgs
Field name=received_msgs
Field name=sent_bytes
Field name=received_bytes
Field name=probe_handler
Exception in thread "main" java.lang.NoClassDefFoundError: org/jgroups/JChannel
        at myA.loader.start(loader.java:23)
        at myA.loader.main(loader.java:45)
Caused by: java.lang.ClassNotFoundException: org.jgroups.JChannel
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
        ... 2 more

I don't understand why the printout shows that the class is loaded but then it is not found?

Your code has maybe a couple of problems. First, you instantiate the loader 2 times within main, so the second instance is independent from the first one and might not be aware that the first one loaded the class file definition of JChannel.

Moreover you've defined JChannel as a member of loader before, therefore the JRE should require the class definition for it at startup - else it should not know what this field should be. I've replaced it with the class you've loaded via the URLClassLoader which you should instantiate in start().

package myA;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import org.jgroups.JChannel;
public class Loader 
    Class<?> clazz;
    String user_name=System.getProperty("user.name", "n/a");
    private void start() throws Exception 
        if (this.clazz == null)
            throw new Exception("Channel class was not loaded properly");
        Object channel  = this.clazz.newInstance(); // use the default config, udp.xml
        Method chatCluster = this.clazz.getDeclaredMethod("connect", new Class[] { String.class });
        chatCluster.invoke(channel, "ChatCluster");
    public void loadMe() throws Exception
        URL classUrl;
        classUrl = new URL("file:///home/myJars/jgroups-3.4.2.Final.jar");
        URL[] classUrls = { classUrl };
        URLClassLoader ucl = new URLClassLoader(classUrls);
        Class<?> c = ucl.loadClass("org.jgroups.JChannel");
        for(Field f: c.getDeclaredFields()) 
            System.out.println("Field name=" + f.getName());
        this.clazz = c;
        Object instance = c.newInstance();  
        //Method theMethod = c.getMethod("main");
        //theMethod.invoke(instance);
     public static void main(String[] args) throws Exception 
         Loader loader = new Loader();
         loader.loadMe();
         loader.start();

You should further add some error handling to the code.

@Vottner, thanks for the code, and +1 for clarity as I was struggling to understand the earlier comments. Can I use the same logic to make the jar available before calling the Loader class. ie if I have parentA.class that loads the Object channel = this.clazz.newInstance() then calls Loader.class, will it still be available to Loader?thx Art – art vanderlay Jan 12, 2014 at 23:06 I'm not totally sure what you are trying to achieve, TBH. Instead of dynamically loading the jar during runtime you could load it at startup time by providing the jar in the classpath of the java -cp command (if your code is within a jar file you could even add a Class-Path: TheDependentJarToLoad.jar entry to the MANIFEST.MF of the hosting jar-file so you can use java -jar yourJarFile.jar). Here you simply can instantiate new instances using new JChannel() instead of using reflection and classloaders. – Roman Vottner Jan 13, 2014 at 8:34 Please clarify what you mean with make the jar available before calling the Loader class. Refactoring the start() method to a parent class does not make that much sense as the method contains a further invocation of connect("ChatCluster"); method which might only be available for the JChannel class. You could refactor loadMe() to the (abstract) parent and add a parameter for the method which defines the name of the class to load and stores it into a protected Class clazz; field which you can use in the child to instantiate an object of the required class. – Roman Vottner Jan 13, 2014 at 8:44
Exception in thread "main" java.lang.NoClassDefFoundError: org/jgroups/JChannel
    at myA.loader.start(loader.java:23)

The code fails on this line:

       channel=new JChannel(); // use the default config, udp.xml

The type JChannel is not visible to loader's ClassLoader. This will be obvious if you try:

       loader.class
             .getClassLoader()
             .loadClass("org.jgroups.JChannel");

You should not have any compile-time references to a dependency that will not be on the type's classpath at runtime.

Loading with a new child ClassLoader does not add that type to some global class pool. The loaders are hierarchical with child-parent relationships.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.