Search code examples
javajarclassloaderclassnotfoundexceptionurlclassloader

Error when load JAR file classes at run time


I am trying to add JAR file to class path and load all classes from JAR file at run time. here is the code I wrote for this task (This class extends URLClassLoader)

public void loadJar(final String fName) throws IOException, IllegalAccessException, ClassNotFoundException {
    final File file = new File(fName);
    if (file.exists() && getFileExtension(file.getName()).equalsIgnoreCase("jar")) {
        addURL(file.toURI().toURL());
        for(final URL url : getURLs()){
            System.out.println(url.toString());
        }
        final ZipFile jarFile = new ZipFile(file, ZipFile.OPEN_READ);
        final Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) jarFile.entries();
        while (entries.hasMoreElements()) {
            final String className = getClassCanonicalName(entries.nextElement());
            if (className != null) {
                loadClass(getClassCanonicalName(entries.nextElement()));
            }
        }
    }
}

private String getFileExtension(final String fileName) {
    return fileName.substring(fileName.lastIndexOf(".") + 1);
}

private String getClassCanonicalName(final ZipEntry entry) {
    final String entryName = entry.getName();
    if (getFileExtension(entryName).toLowerCase().endsWith("class")) {
        return entryName.replaceAll(File.separator, ".");
    } else {
        return null;
    }
}

But I keep getting ClassNotFoundException for class entities even through getURLs does indicate jar files has been added to this loader.

What is the cause of this problem? Thanks


Solution

  • return entryName.replaceAll(File.separator, "."); 
    

    On Windows this will fail. It should be / for the separator of a ZipEntry for a Zip made on any platform.

    So replace that with:

    return entryName.replaceAll("/", "."); 
    

    Also strip the class name. SSCCE E.G.:

    import java.io.*;
    import java.net.*;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipInputStream;
    
    public class URLClassLoaderTest extends URLClassLoader {
    
        public URLClassLoaderTest(URL[] arg0) {
            super(arg0);
        }
    
        public void loadJar(URL urlOfJar) throws IOException, IllegalAccessException, ClassNotFoundException {
            if (getFileExtension(urlOfJar.getFile()).equalsIgnoreCase("jar")) {
                addURL(urlOfJar);
                for(final URL url : getURLs()){
                    System.out.println(url.toString());
                }
                final ZipInputStream zis = new ZipInputStream(urlOfJar.openStream());
                ZipEntry ze = zis.getNextEntry();
                while (ze!=null) {
                    final String className = getClassCanonicalName(ze);
                    if (className != null) {
                        loadClass(getClassCanonicalName(ze));
                    }
                    ze = zis.getNextEntry();
                }
            }
        }
    
        private String getFileExtension(final String fileName) {
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        }
    
        private String getClassCanonicalName(final ZipEntry entry) {
            final String entryName = entry.getName();
            if (getFileExtension(entryName).toLowerCase().endsWith("class")) {
                String s = entryName.substring(0,entryName.length()-6);
                s = s.replaceAll("/", ".");
                System.out.println(s);
                return s;
            } else {
                return null;
            }
        }
    
        public static void main(String[] args) throws Exception {
            URL[] url = {new URL("http://pscode.org/lib/mime.jar")};
            URLClassLoaderTest uclt = new URLClassLoaderTest(url);
            uclt.loadJar(url[0]);
        }
    }
    

    Output

    http://pscode.org/lib/mime.jar
    org.pscode.mime.MimeType$1
    org.pscode.mime.MimeType$1
    org.pscode.mime.MimeType$2
    org.pscode.mime.MimeType$2
    org.pscode.mime.MimeType
    org.pscode.mime.MimeType