4

I have a problem, I wish to use reflection to generate instances of one of a set of classes at runtime. However, I have hit a snag. I want to get all of the classes involved to register themselves so the appropriate class can be chosen from a GUI. I can do this using a static code block in each file which provides a tidy OO solution. However, the java class loader specifically loads classes when they are required, hence if a needed class has not yet been used, it is not registered.

Short of directly providing a static list of names, or running through the underlying class/java files (which would break when packaged into a jar anyway), is there any way to force classes of certain packages to be loaded?

Basically, I want the ability to add new classes, from a specified superclass, without having to change/add any other code.

3

7 Answers 7

3

To clarify, your problem isn't about "dynamic class loading in Java", it's about dynamic class enumeration -- you know how to load classes, you just don't know what classes you want.

A quick Google came up with this page: http://forums.sun.com/thread.jspa?threadID=341935&start=0&tstart=0

Taken from that page, here's some sample code that ought to work:

public static Class[] getClasses(String pckgname)
        throws ClassNotFoundException {
    ArrayList<Class> classes = new ArrayList<Class>();
    // Get a File object for the package
    File directory = null;
    try {
        ClassLoader cld = Thread.currentThread().getContextClassLoader();
        if (cld == null) {
            throw new ClassNotFoundException("Can't get class loader.");
        }
        String path = '/' + pckgname.replace('.', '/');
        URL resource = cld.getResource(path);
        if (resource == null) {
            throw new ClassNotFoundException("No resource for " + path);
        }
        directory = new File(resource.getFile());
    } catch (NullPointerException x) {
        throw new ClassNotFoundException(pckgname + " (" + directory
                + ") does not appear to be a valid package");
    }
    if (directory.exists()) {
        // Get the list of the files contained in the package
        String[] files = directory.list();
        for (int i = 0; i < files.length; i++) {
            // we are only interested in .class files
            if (files[i].endsWith(".class")) {
                // removes the .class extension
                classes.add(Class.forName(pckgname + '.'
                        + files[i].substring(0, files[i].length() - 6)));
            }
        }
    } else {
        throw new ClassNotFoundException(pckgname
                + " does not appear to be a valid package");
    }
    Class[] classesA = new Class[classes.size()];
    classes.toArray(classesA);
    return classesA;
}
Sign up to request clarification or add additional context in comments.

2 Comments

@Hubris: Ohh noooo.. that's a) running through the file system and it's ugly and breaks DRY... : stackoverflow.com/questions/1275113/…
@Daniel: Just in case you didn't notice in your finding you ARE loading the classes anyway with: classes.add( Class.forName( .....
2

Spring Framework does component scanning based on annotations.

Take a look at ClassPathScanningCandidateComponentProvider class, for example. You can do the same thing based on interface / base class and it should work for all LOCAL classes. There is no way to do this for ALL classes in java.

Comments

1

Class.forName("class name here");

You'll have a String variable with the class name. Assuming you have a List of Strings containing all class names you want to be loaded (and automatically registered using static code blocks:

for(String className : classesToBeLoaded) Class.forName(className);

2 Comments

I think you misunderstand... I don't want to provide a static name.
It is not static. I showed you how (after edit). If you want to list every class in a package, it's impossible if you don't iterate through the file system. By design, the class loaders in Java cannot list classes (think about a HTTP-based class loader), but if you know you'll use the default classloader, you can browse all the folders and all the jars (which are zip files) for the classes belonging to your packages. Anyway, providing the list of classes as configuration/input for your program is safer and easier to implement.
1

Go through this example:

public class MainClass {

  public static void main(String[] args){

    ClassLoader classLoader = MainClass.class.getClassLoader();

    try {
        Class aClass = classLoader.loadClass("com.jenkov.MyClass");
        System.out.println("aClass.getName() = " + aClass.getName());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

}

1 Comment

Yes, this works, but in order to do it, you have to have a static list of class names...
1

There is a chance if your classes are in jars in the filesystem ( this may sound ridiculous but I've seen classes loaded from ldaps )

So, again if your classes are in the filesystem inside jars you can do the following:

Pseudo-java below:

  String classPath = System.getClassPath(); 
  String [] classPathParts = classpath.split(";"); // or :

  String [] allTheClasses = []

  for each ( file  in classPathParts ) {
      if( file is directory ) {
           allTheClasses.addAll( file.contents );
      } else if ( file is ".jar" ) {
           allTheClasses.addAll( getZippedNamesFrom( file ) );

      }
 }

 // At this point you would have all the classes in the array ( list ) .

 String [] packageNames = {"a.b.c", "d.e.f" };
 for each ( String  clazzName in allTheClasses ) {
       if ( packageNames.contains( clazzName.getPackageName() ) ) {
           Class.forName( clazzName ); // load it and have the static block run
           // Or run it your self
       }
 }

 // End of the story.

I did this for a similar thing a long while ago.

I use to load about 70k+ classes names using this approach in less than a second. In my case I was dynamically looking for about 10 classes so the whole process took me about 1.1 second.

Comments

1

You can use ClassFinder,

http://jmeter.apache.org/api/org/apache/jorphan/reflect/ClassFinder.html

Comments

0

I would suggest putting all the "dynamic" classes into one package. Scan that directory to pull out each filename and then use that in Class.forName() to load and register each class.

I just asked a similar question yesterday, and got some good feedback.

Create new class from a Variable in Java

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.