Pregunta

I am using URLClassLoader for loading classes.

Though the name of the file which i pass is loaded successfully but for classes which it referes to, NoClassDefFoundError is thrown for those. Both the classes are part of different jar files.

Even more strange stuff is same piece of code is working fine on windows but it is throwing error on Linux.

Here is the code I am using:

package com.pb.spectrum.lim.upgrade.common;

 import java.io.File;
 import java.io.FilenameFilter;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.List;

 public class ClassInvoker {

public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    if(args.length < 2){
        throw new IllegalArgumentException("First argument should be Class name. Second argument should be jar's directory. Rest of the arguments passed to main method of invoked class.");
    }

    File jarsDir = new File(args[1]);
    if(!jarsDir.isDirectory()){
        throw new IllegalArgumentException("Second argument should point to jar's directory.");
    }

    URLClassLoader urlClassLoader = null;

    List<URL> urls = new ArrayList<URL>();
    File[] files = jarsDir.listFiles(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return name.toLowerCase().endsWith(".jar");
        }
    });

    for(File jarFile : files){
        urls.add(jarFile.toURI().toURL());
    }
    urlClassLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]));

    Thread.currentThread().setContextClassLoader(urlClassLoader);

    Object[] params = new String[args.length-2];

    // First 2 arguments are not required for class to be invoked.
    System.arraycopy(args, 2, params, 0, params.length);

    for(Object string : params){
        System.out.println("Param ---->" + (String)string);
    }

    Class clazz = urlClassLoader.loadClass(args[0]);
    Method method = clazz.getMethod("main", new Class[]{String[].class});
    method.invoke(null, new Object[] {params});
}
    }

Now If i pass class to be loaded as A.B.MyClass1 it loads successfully but it fails to load A.B.MyClass2 which is in seperate jar file.

¿Fue útil?

Solución

Well my problem is solved but i am not sure about the cause of this issue.

To summarize:

Sequence of jars being loaded was causing the issue. In my particular case sorting the order of jars before giving the list to URLClassLoader solves the problem.

But it raises another question

Here are the details

I have two jar files with same package structure, like A.B but only one of them is having MyClass2. Now cause of issue was jar not having MyClass2 was loaded before jar having MyClass2 and somehow(i don't know how or why) URLClassLoader sees the first jar having the package A.B but not having MyClass2 class and throws NoClassDefFoundError. After sorting jar having MyClass2 is loaded first and ClassLoader is bale to locate the class.

I am not sure about this behavior. I myself is confused with it.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top