3

The code is as follows

what it does is it loads all the classes inside a jar file which I placed inside my home directory .

import java.io.File;
import java.util.jar.JarFile;
import java.util.jar.JarEntry;
import java.net.URLClassLoader;
import java.net.URL;
import java.util.Enumeration;
import java.lang.ClassLoader;
public class Plugin extends ClassLoader {
public static void main(String[] args) throws Exception {

    File file = new File(System.getProperty("user.home") + "/HelloWorld.jar");

    URLClassLoader clazzLoader = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()});

    JarFile jarFile = new JarFile(file);
    Enumeration<JarEntry> entries = jarFile.entries();

    while (entries.hasMoreElements()) {
        JarEntry element = entries.nextElement();
        if (element.getName().endsWith(".class")) {
            try {
                Class c = clazzLoader.loadClass(element.getName().replaceAll(".class", "").replaceAll("/", "."));
                c.newInstance(); // this proves that class is loaded
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    Class cls = Class.forName("HelloWorld");
    cls.newInstance();
    Plugin p = new Plugin();
    p.checkIfLoaded();

}

public void checkIfLoaded() {
System.out.println("coming in");
if (findLoadedClass("HelloWorld") != null){
        System.out.println("Yepee, HelloWorld class is loaded !");
}
}

}

My HelloWorld is as in https://github.com/HarishAtGitHub/doc/blob/master/makeExecutableJar/HelloWorld.java

and the jar is got using the instructions in my github account mentioned above .

c.newInstance() works .

How did I confirm ?

the static block got executed ...

but Class.forName("HelloWorld") throws ClassNotFoundException

also findLoadedClass("HelloWorld") is null ..

I cannot understand why this strange behaviour ?

Please guide ...

Abimaran Kugathasan
  • 31,165
  • 11
  • 75
  • 105
Harish Kayarohanam
  • 3,886
  • 4
  • 31
  • 55

2 Answers2

3

This is a classloader issue.

As per the Javadocs to Class.forName, you are looking up the class using the classloader of the current class. As your main class, this will be the JVM's bootstrap classloader (and will more or less just include the standard library plus anything you provided as a -cp command line argument). It is not going to delegate to the classloader that you instantiated as a local variable, and so will not return classes that that classloader could find.

If you were to specify the classloader explicitly, and call

Class.forName("HelloWorld", true, clazzloader)

then the classloader you just created will be searched instead and your class should be found.

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
  • ya . so is not possible to check from anywhere if my class was loaded ? should my clazzLoader be passed around always ? are the loaded class information kept in a common place ? – Harish Kayarohanam Feb 13 '14 at 09:40
  • The easiest way to handle this particular situation, is to have your classes loaded by the bootstrap (i.e. main) classloader. If you pass the `HelloWorld.jar` as a `-cp` argument to your Java invocation, the classes in it will be automatically loaded by the main classloader, you won't need to do anything else. (Or if the app itself is a JAR, you can set the `Class-Path` property of its manifest.) – Andrzej Doyle Feb 13 '14 at 09:50
  • Otherwise, if you **need** to create a classloader at runtime (for whatever reason), you'll probably want to set it as a [Thread's context classloader](http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#setContextClassLoader(java.lang.ClassLoader)) for a relatively easy way to pass it around. You will probably still need some manual work to get classes loader from it though, since by default a class' own classloader is used to look up other classes. If you want any other behaviour, you'll normally need to specify the classloader explicitly. – Andrzej Doyle Feb 13 '14 at 09:52
2

Because Class.forName(String) uses currentClassLoader and you have load the class in different ClassLoader.

According with javadoc, invoking Class.forName(String) is equivalent to:

Class.forName(className, true, currentLoader) 
rdllopes
  • 4,897
  • 4
  • 19
  • 36