0

How can I locate (and instantiate) a class in Java when I only have its name but not its package? The code

Class<?> clazz = Class.forName( "className" );

throws a ClassNotFoundException althout "className" is on the classpath. It only works with the complete package name. The code

URL url = SomeClass.getClass().getClassLoader().findResource( "className.class" );

returns null.

This is not a duplicate since the solutions which are using package lists are not answering the question "without package". Instead they rely on a predefined or externally configured list of packages. So "Finding a class reflectively by its simple-name alone" is not a duplicate but provides a solution which invloves packages.

Are there any Java methods available to achieve this?

My own answer would be:

No. Neither Class nor ClassLoader or any other Java class provides this functionality. I have written a small class to solve this. The last line from System.out.println gives the location of the class. Please feel free to use and adapt it to your requirements.

package com.lemcke.util;

import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassLocator {

/**
 * Locates a class by its name. Searches the whole {@code classpath}.
 * 
 * @param name
 *            Name of the class (without package)
 * @return full package name of the class or {@code null} if not found
 */
public String locateClass( String name ) throws IOException {
    if ( name == null || name.length() == 0 ) {
        return null;
    }
    if ( name.endsWith( ".class" ) == false ) {
        name += ".class";
    }
    String found = null;
    String cp = System.getProperty( "java.class.path" );
    String[] paths = cp.split( "[,;]" );

    for ( String pathname : paths ) {
        System.out.println( pathname );
        if ( pathname.endsWith( ".jar" ) ) {
            found = locateClassInJar( name, pathname );
            if ( found != null ) {
                break;
            }
        } else {
            found = locateClassInFolder( name, new File( pathname ) );
            if ( found != null ) {
                found = found.substring( pathname.length() + 1 );
                break;
            }
        }
    }
    if ( found != null ) {
        found = found.substring( 0, found.length() - ".class".length() )
                .replace( '/', '.' ).replace( '\\', '.' );
    }
    return found;
}

private String locateClassInFolder( String name, File path )
        throws IOException {
    File f = new File( path + "/" + name );
    if ( f.exists() ) {
        return f.getPath();
    }
    String found = null;
    for ( File entry : path.listFiles() ) {
        if ( entry.isDirectory() ) {
            System.out.println( entry );
            found = locateClassInFolder( name, entry );
            if ( found != null ) {
                break;
            }
        }
    }
    return found;
}

private String locateClassInJar( String name, String jarpath )
        throws IOException {
    name = "/" + name;
    JarFile jarFile = new JarFile( jarpath );
    Enumeration<JarEntry> entries = jarFile.entries();
    String found = null, entry = null;
    while ( entries.hasMoreElements() ) {
        entry = entries.nextElement().getName();
        if ( entry.endsWith( name ) ) {
            found = entry;
            break;
        }
    }
    jarFile.close();
    return found;
}

/**
 * @param args
 * @throws IOException
 */
public static void main( String[] args ) throws IOException {
    ClassLocator locator = new ClassLocator();
    String found = locator.locateClass( args[0] );
    System.out.println( "found = " + found );
}

}

Jemolah
  • 1,962
  • 3
  • 24
  • 41

1 Answers1

0

In general situation there is no way to load class by partial name.

In practice it is possible, but not easy. You can look in spring source code to check how they achieve this.

talex
  • 17,973
  • 3
  • 29
  • 66