35

I'm playing around with Reflection and I thought I'd make something which loads a class and prints the names of all fields in the class. I've made a small hello world type of class to have something to inspect:

kent@rat:~/eclipsews/SmallExample/bin$ ls
IndependentClass.class
kent@rat:~/eclipsews/SmallExample/bin$ java IndependentClass 
Hello! Goodbye!
kent@rat:~/eclipsews/SmallExample/bin$ pwd
/home/kent/eclipsews/SmallExample/bin
kent@rat:~/eclipsews/SmallExample/bin$ 

Based on the above I draw two conclusions:

  • It exists at /home/kent/eclipsews/SmallExample/bin/IndependentClass.class
  • It works! (So it must be a proper .class-file which can be loaded by a class loader)

Then the code which is to use Reflection: (Line which causes an exception is marked)

import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class InspectClass {
    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws ClassNotFoundException, MalformedURLException {
        URL classUrl;
        classUrl = new URL("file:///home/kent/eclipsews/SmallExample/bin/IndependentClass.class");
        URL[] classUrls = { classUrl };
        URLClassLoader ucl = new URLClassLoader(classUrls);
        Class c = ucl.loadClass("IndependentClass"); // LINE 14
        for(Field f: c.getDeclaredFields()) {
            System.out.println("Field name" + f.getName());
        }
    }
}

But when I run it I get:

Exception in thread "main" java.lang.ClassNotFoundException: IndependentClass
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
    at InspectClass.main(InspectClass.java:14)

My questions:

  1. What am I doing wrong above? How do I fix it?
  2. Is there a way to load several class files and iterate over them?
  • What are you suppressing warnings? – Tom Hawtin - tackline Apr 10 '09 at 19:12
  • 1
    A common mistake is to use the current directory as the URL, but also use the current directory for your normal classes. Because the default parent is the system class loader, your class loader doesn't get a chance to load the class. – Tom Hawtin - tackline Apr 10 '09 at 19:13
  • file:///home/kent/eclipsews/SmallExample/bins/IndependentClass.class it should be: file:///home/kent/eclipsews/SmallExample/bin/IndependentClass.class ? – dfa Apr 10 '09 at 19:50
  • Tom hawtin: Yes, Class is a raw type. It's what I want though as I'm continuing to build on it and want to be able to load any class. So I'm suppressing that warning. I'll keep that common mistake in mind, I'm sure I'll do it pretty soon. :-) davide: Yes, it was a typo. I corrected it now. –  Apr 10 '09 at 19:54
  • Both answers were correct. I gave my accepted answer to the one with most information. I'd rather accept both. Well.. –  Apr 10 '09 at 19:55

5 Answers5

45

From the Javadocs for the URLClassLoader(URL[]) constructor:

Constructs a new URLClassLoader for the specified URLs using the default delegation parent ClassLoader. The URLs will be searched in the order specified for classes and resources after first searching in the parent class loader. Any URL that ends with a '/' is assumed to refer to a directory. Otherwise, the URL is assumed to refer to a JAR file which will be downloaded and opened as needed.

So you have two options:

  1. Refer to the directory that the .class file is in
  2. Put the .class file into a JAR and refer to that

(1) is easier in this case, but (2) can be handy if you're using networked resources.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
12

You must provide the directories or the jar files containing your .class files to the URLClassLoader:

classUrl = new URL("file:///home/kent/eclipsews/SmallExample/bin/");

And yes, you can load as many classes as you like

Maurice Perry
  • 32,610
  • 9
  • 70
  • 97
7

You have to load the class by giving the fully qualified class name that is class name with with its package path as,

Class c = ucl.loadClass("com.mypackage.IndependentClass");
Umesh Aawte
  • 4,590
  • 7
  • 41
  • 51
Suresh
  • 79
  • 1
  • 1
0

I was having a similar problem but my class file was residing inside a package named "customElements". In such scenarios the URL needs to be constructed till the folder just above the root package and in the load method the complete name of the class including the package should be passed. For example, in my case; URL was like:

File customElementsDir = new File("D:/My Space");
//File customElementsDir = new File("D:\\customElements");
URL[] urls = null;
try {
    URL url = customElementsDir.toURI().toURL();
    urls = new URL[] { url };
} catch (MalformedURLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

And actual loading was like:

clazz = childFirstClassLoader
            .loadClass("customElements.CustomLoadableClass");

Where childFirstClassLoader is my classloader.

Eli_B
  • 163
  • 2
  • 10
CoolCoder
  • 9
  • 1
0

I had the same problem but I found this as a solution:

System.getProperty("java.class.path")

This give you the jar, and classes path. From here you are able to manage your process.

zuluk
  • 1,557
  • 8
  • 29
  • 49