简体   繁体   中英

Java java.lang.NoClassDefFoundError whilie loading jars in Module Loader

Ich have wrote a little module system, where modules are packaged into jars. The application has to load these modules at start. For loading these jars and extract the classes which implements the IModule interface or extends the Module class, i have written an ModuleLoader, by inspiring an tutorial. The class Module is also implementing the IModule interface.

Now, if i start the application, there is thrown an exception.

IModuleLoader moduleLoader = new DefaultModuleLoader();
        List<IModule> moduleList = moduleLoader.loadModulesFromDir(moduleDir);

Exception:

Exception in thread "main" java.lang.NoClassDefFoundError: com/corundumstudio/socketio/AuthorizationListener
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:455)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:367)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at com.jukusoft.jbackendengine.backendengine.module.impl.DefaultModuleLoader.extractClassesFromJAR(DefaultModuleLoader.java:137)
at com.jukusoft.jbackendengine.backendengine.module.impl.DefaultModuleLoader.extractClassesFromJARs(DefaultModuleLoader.java:120)
at com.jukusoft.jbackendengine.backendengine.module.impl.DefaultModuleLoader.loadModulesFromDir(DefaultModuleLoader.java:43)
at com.jukusoft.jbackendengine.backendengine.module.impl.DefaultModuleManager.loadModulesFromDir(DefaultModuleManager.java:91)
at com.jukusoft.jbackendengine.backendengine.module.impl.DefaultModuleManager.loadAndStart(DefaultModuleManager.java:100)
at com.jukusoft.jbackendengine.backendengine.builder.DefaultBackendEngineBuilder.buildBackendEngine(DefaultBackendEngineBuilder.java:26)
at com.jukusoft.jbackendengine.backendengine.builder.DefaultBackendEngineBuilder.buildBackendEngine(DefaultBackendEngineBuilder.java:16)
at com.jukusoft.jbackendengine.backendengine.factory.BackendEngineFactory.createNewDefaultBackendEngine(BackendEngineFactory.java:22)
at com.jukusoft.jbackendengine.backendengine.ServerEngineMain.main(ServerEngineMain.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
 Caused by: java.lang.ClassNotFoundException: com.corundumstudio.socketio.AuthorizationListener
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 25 more

Here is the code of class ModuleLoader:

 package com.jukusoft.jbackendengine.backendengine.module.impl;

 import com.jukusoft.jbackendengine.backendengine.module.IModule;
 import com.jukusoft.jbackendengine.backendengine.module.IModuleLoader;
 import com.jukusoft.jbackendengine.backendengine.module.ModuleUtils;

 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FilenameFilter;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;

 /**
  * Created by Justin on 03.07.2015.
  */
 public class DefaultModuleLoader implements IModuleLoader {

@Override
public List<IModule> loadModulesFromDir(File modulesDir) throws IOException {
    FilenameFilter filenameFilter = new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return name.endsWith(".jar") || name.endsWith(".jam");
        }
    };

    if (!modulesDir.exists()) {
        System.out.println("directory modules doesnt exists, creating directory modules.");
        modulesDir.mkdirs();
    }

    File[] files = modulesDir.listFiles(filenameFilter);

    System.out.println("" + files.length + " .jar files in directory " + modulesDir.getAbsolutePath() + " found.");

    ClassLoader classLoader = new URLClassLoader(fileArrayToURLs(files));
    List<Class<IModule>> moduleClasses = extractClassesFromJARs(files, classLoader);

    System.out.println("" + moduleClasses.size() + " modules found.");

    return createModuleObjects(moduleClasses);
}

@Override
public List<IModule> loadModulesFromFile(File moduleFile) throws IOException {
    ClassLoader classLoader = new URLClassLoader(fileToURL(moduleFile));
    List<Class<IModule>> moduleClasses = extractClassesFromJAR(moduleFile, classLoader);
    return createModuleObjects(moduleClasses);
}

private URL[] fileArrayToURLs (File[] files) throws MalformedURLException {

    URL[] urlsArray = new URL[files.length];

    for (int i = 0; i < files.length; i++) {
        urlsArray[i] = files[i].toURI().toURL();
    }

    return urlsArray;
}

private URL[] fileToURL (File file) throws MalformedURLException {
    URL[] urlsArray = new URL[1];
    urlsArray[0] = file.toURI().toURL();
    return urlsArray;
}

public boolean isModuleClass (Class<?> cls) {
    //System.out.println("isModuleClass() " + cls.getName() + ".");

    /*try {
        for (Class<?> cls1 : cls.getInterfaces()) {
            System.out.println("Found interface " + cls1.getName() + " in class " + cls.getName() + ".");

            if ((cls1.equals(IModule.class) || cls1.equals(Module.class)) && ModuleUtils.containsModuleInfo(cls)) {
                return true;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }*/

    return IModule.class.isAssignableFrom(cls) || Module.class.isAssignableFrom(cls);
}

public IModule createModuleObject (Class<IModule> moduleClass) throws IllegalAccessException, InstantiationException {
    return moduleClass.newInstance();
}

private List<IModule> createModuleObjects(List<Class<IModule>> classList) {

    List<IModule> modules = new ArrayList<IModule>(classList.size());

    for (Class<IModule> module : classList) {
        try {
            modules.add(module.newInstance());
        } catch (InstantiationException e) {
            System.err.println("Cannot create new instance of class " + module.getName() + ".");
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            System.err.println("IllegalAccess for module: " + module.getName() + ".");
            e.printStackTrace();
        }
    }

    return modules;
}

private List<Class<IModule>> extractClassesFromJARs(File[] jars, ClassLoader cl) throws IOException {

    List<Class<IModule>> classList = new ArrayList<Class<IModule>>();

    for (File jar : jars) {
        classList.addAll(extractClassesFromJAR(jar, cl));
    }

    return classList;
}

@SuppressWarnings("unchecked")
private List<Class<IModule>> extractClassesFromJAR(File jarFile, ClassLoader classLoader) throws IOException {

    List<Class<IModule>> classList = new ArrayList<Class<IModule>>();

    JarInputStream jarInputStream = new JarInputStream(new FileInputStream(jarFile));
    JarEntry ent = null;

    while ((ent = jarInputStream.getNextJarEntry()) != null) {
        if (ent.getName().toLowerCase().endsWith(".class")) {
            try {
                Class<?> cls = classLoader.loadClass(ent.getName().substring(0, ent.getName().length() - 6).replace('/', '.'));

                if (isModuleClass(cls)) {
                    classList.add((Class<IModule>) cls);
                }
            } catch (ClassNotFoundException e) {
                System.err.println("Cannot load class " + ent.getName() + ".");
                //e.printStackTrace();
            }
        }
    }

    jarInputStream.close();
    return classList;
}

}

the difference between ClassNotFoundException and NoClassDefFoundError are that the first happens because the named class can't be found on the classpath, the second (which is what you have) occurs when a class can be found but that some other error happens when the class is loaded. With this in mind perhaps there's a static piece of code or initialised member variable that's causing an exception. I have a vague recollection that a class I had once caused this error because I declared and initialised a variable to a resource that at runtime was null ie InputStream in = blah.class.getResourceAsStream(..blah...) so when my class that had in as a member was loaded it threw an NPE.

Helps if I actually read the whole stack trace before answering, yes the def error is caused by the ClassNotFoundException which makes things easier it just means that Authorization class isn't accessible on the classpath

Is

<dependency>
    <groupId>com.corundumstudio.socketio</groupId>
    <artifactId>netty-socketio</artifactId>
</dependency>

present in your maven pom.xml? If yes, try to add corresponding netty-socketio***.jar to classpath where your run your program.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM