Not exactly a timely post, but here is code to find all subclasses of a class (or all implementors of an interface) on your classpath.
To use it, add these classes to your classpath and from somewhere in your program call:
Class[] interestingClasses = Subclasses.of( MyInterface.class );
// or add a regex
Class[] interestingClasses = Subclasses.of( MyClass.class, ".*Suffix$ );
Once you have the array of classes you can instantiate them with relfection, but I beleive that only works if your class has an empty constructor.
import java.util.ArrayList;
import java.util.Iterator;
/**
* Created with Eclipse
* User: duncanIdaho for java-gaming.org
*
* copyright 2004
*/
/**
* A class to find all subclasses of a given <code>Class</code> or interface.
*
*/
public class Subclasses {
/**
* Find all subclasses of the given <code>Class</code> or interface by
* loading all classes on the class path.
*
* @param targetType the superclass of all returned classes.
* @return an array of all subclasses of <code>targetType</code>
*/
public static Class[] of( Class targetType ) {
return of( targetType, ".*" );
}
/**
* Find all subclasses of the given <code>Class</code> or interface by
* loading only those classes with names that match the given regular
* expression.
*
* @param targetType the superclass of all returned classes.
* @param regex a regular expression that will match with every subclass
* @return an array of all subclasses of <code>targetType</code>
*/
public static Class[] of( Class targetType, String regex ) {
ArrayList matches = new ArrayList();
ClassPath cp = new ClassPath();
Iterator i = cp.classNameIterator();
while ( i.hasNext() ) {
String className = (String)i.next();
if ( className.matches( regex ) &&
!className.equals( targetType.getName() ) ) {
Class clazz = null;
try {
clazz = Class.forName( className );
} catch (ClassNotFoundException cnfx ) {
continue;
} finally {
if ( clazz != null && targetType.isAssignableFrom( clazz ) ) {
matches.add( clazz );
}
}
}
}
return (Class[])matches.toArray( new Class[0] );
}
}
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* Created with Eclipse
* User: duncanIdaho for java-gaming.org
*
* copyright 2004
*/
/**
* ClassPath find and records the fully qualified name of every Class
* on the classpath via the system property "java.class.path".
*
*/
public class ClassPath {
public static final int SILENT = 0;
public static final int QUIET = 1;
public static final int VERBOSE = 2;
public static final String JAR_EXT = ".jar";
public static final String ZIP_EXT = ".zip";
public static final String CLASS_EXT = ".class";
private ArrayList classNames;
private int outputLevel;
/**
* create a new ClassPath instance and find all classes on the classpath
*
*/
public ClassPath() {
this( SILENT );
}
public ClassPath(int type) {
super();
outputLevel = type;
findAllClassNames();
}
/**
* Answers an <code>Iterator</code> over fully qualified <code>Class</code>
* names found on the classpath.
* @return an <code>Iterator</code> over the elements in this list
*/
public Iterator classNameIterator() {
return classNames.iterator();
}
/**
* Answers an <code>ArrayList</code> of all <code>Class</code> names found
* on the classpath.
* @return an <code>ArrayList</code> of class names.
*/
public ArrayList getClassNames() {
return classNames;
}
/**
* Initialize the member variable <code>classNames</code> and
* look for classes.
*
*/
private void findAllClassNames() {
String path = null;
classNames = new ArrayList();
try {
path = System.getProperty( "java.class.path" );
} catch ( Exception x ) {
x.printStackTrace();
}
if ( outputLevel != SILENT )
System.out.println( "scanning classpath: " + path );
StringTokenizer toke = new StringTokenizer( path, File.pathSeparator );
while ( toke.hasMoreTokens()) {
String pathElement = toke.nextToken();
File elementFile = new File( pathElement );
String elementName = elementFile.getAbsolutePath();
if ( elementName.endsWith( JAR_EXT ) ) {
addJarContents( elementFile );
} else if ( elementName.endsWith( ZIP_EXT ) ) {
addZipContents( elementFile );
} else if ( elementName.endsWith( CLASS_EXT ) ) {
addClass( elementFile );
} else {
addDirectoryContents( elementFile );
}
}
if ( outputLevel != SILENT )
System.out.println( "found " + classNames.size() + " classes." );
if ( outputLevel == VERBOSE ) {
Iterator i = classNames.iterator();
while ( i.hasNext() ) {
String name = (String)i.next();
System.out.println( name );
}
}
}
/**
* Adds a file explicitly mentioned on the classpath to the list
* of classes.
* @param classFile a class file listed on the classpath itself.
*/
private void addClass( File classFile ) {
classNames.add( getClassNameFrom( classFile.getName() ) );
}
/**
* Adds all class names found in the jar.
* @param jarFile a jar file explicitly listed on the classpath.
*/
private void addJarContents( File jarFile ) {
JarFile jar = null;
try {
jar = new JarFile( jarFile );
} catch ( IOException iox ) {
// boom!
}
if ( jar != null ) {
Enumeration e = jar.entries();
while (e.hasMoreElements()) {
JarEntry entry = (JarEntry)e.nextElement();
if ( !entry.isDirectory() && entry.getName().endsWith( CLASS_EXT ) ) {
String className = getClassNameFrom( entry.getName() );
classNames.add( className );
}
}
}
}
/**
* Adds all class names found in the zip mentioned
* @param zipFile
*/
private void addZipContents( File zipFile ) {
ZipFile zip = null;
try {
zip = new JarFile( zipFile );
} catch ( IOException iox ) {
}
if ( zip != null ) {
Enumeration e = zip.entries();
while (e.hasMoreElements()) {
ZipEntry entry = (ZipEntry)e.nextElement();
if ( !entry.isDirectory() && entry.getName().endsWith( CLASS_EXT ) ) {
String className = getClassNameFrom( entry.getName() );
classNames.add( className );
}
}
}
}
/**
* This method takes a top level classpath dir i.e. 'classes' or bin
* @param dir
*/
private void addDirectoryContents( File dir ) {
// drill through contained dirs ... this is expected to be the
// 'classes' or 'bin' dir
File files[] = dir.listFiles();
for( int i = 0; i < files.length ; ++i ) {
File f = files[i];
if ( f.isDirectory() ) {
addDirectoryContents( "", f );
} else {
if ( f.getName().endsWith( CLASS_EXT ) )
addClass( f );
}
}
}
/**
* This method does the real directory recursion, passing along the
* the corresponding package-path to this directory.
*
* @param pathTo the preceding path to this directory
* @param dir a directory to search for class files
*/
private void addDirectoryContents( String pathTo, File dir ) {
String pathToHere = pathTo + dir.getName() + File.separator;
File files[] = dir.listFiles();
for( int i = 0; i < files.length ; ++i ) {
File f = files[i];
if ( f.isDirectory() ) {
addDirectoryContents( pathToHere, f );
} else {
if ( f.getName().endsWith( CLASS_EXT ) ) {
String absFilePath = pathToHere + f.getName();
classNames.add( getClassNameFrom( absFilePath ) );
}
}
}
}
/**
* replace ANY slashes with dots and remove the .class at the
* end of the file name.
* @param entryName a file name relative to the classpath. A class
* of package org found in directory bin would be passed into this
* method as "org/MyClass.class"
* @return a fully qualified Class name.
*/
private String getClassNameFrom( String entryName ) {
String foo = new String(entryName).replace( '/', '.' );
foo = foo.replace( '\\', '.' );
return foo.substring( 0, foo.lastIndexOf( '.' ) );
}
}