/*
* @(#)InterfaceFinder.java v0.8, 2009/05/06-2020/2/8
*
* Search the class path for classes which implement a specific interface
*
* Usage: java -cp jar_file;class_folder;. InterfaceFinder interface_name_to_search
*/
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;
import java.util.Stack;
import java.util.HashSet;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
The interface finder is used to find all classes
implementing a specific interface.
The location in search includes all the subdirectories
in the class path. Typical usage is as follows.
List<Class> InterfaceFinder.getAvailableInterfaces("java.util.List");
* @since 0.8
* @version 0.8, 2009/05/06-2020/2/8
* @author Seke Wei
*/
public class InterfaceFinder
{
public static final String version="InterfaceFinder.java v0.8 2020/02/08";
/**
a file lister which uses the depth first strategy
to traverse all files under a given directory.
*/
public static class FileLister implements Enumeration
{
boolean hasMore;
Stack<File> fstack;
/**
constructor for file lister.
@param dir the root directory for search.
*/
public FileLister(File dir)
{
fstack = new Stack<>();
if(dir.isDirectory())
fstack.push(dir);
hasMore = true;
}
/**
check if there is still file available for listing.
@return true for elements available and false for otherwise.
*/
public boolean hasMoreElements()
{
return hasMore;
}
/**
get the next available file.
directories are skipped.
@return the file.
*/
public File nextElement()
{
File next = null;
while(fstack.empty()==false)
{
next = (File) fstack.pop();
if(next.isFile())
break;
for(File f : next.listFiles())
fstack.push(f);
}
if(fstack.empty()) hasMore=false;
return next;
}
}
/**
get classes from a jar file which implements an interface.
@param jarFileName the jar filename.
@param iface the interface in search.
@return the set of classes in jar implementing the interface.
*/
public static List<Class> getClassesFromJARFile(String jarFileName, Class iface)
{
final List<Class> classes = new Vector<>();
JarInputStream jarFile = null;
String className = "";
try
{
jarFile = new JarInputStream(new FileInputStream(jarFileName));
JarEntry jarEntry;
while(true)
{
jarEntry = jarFile.getNextJarEntry();
if(jarEntry == null) break;
className = jarEntry.toString();
//System.err.println(className);
if(className.endsWith(".class") && className.indexOf("$") < 0 )
{
//extractClassFromJar(jar, packageName, classes, jarEntry)
className = className.replace('/','.');
className = className.substring(0, className.length() - ".class".length());
Class cl = Class.forName(className);
if(iface.isAssignableFrom(cl))
{
//System.err.println("\t"+className+" can be assigned to "+iface);
classes.add(cl);
}
}
}
jarFile.close();
}
catch (IOException ioe)
{
System.err.println("Unable to get Jar input stream from '"+jarFileName+"'"+ioe);
}
catch (ClassNotFoundException cnfe)
{
System.err.println("unable to find class named " + className.replace('/', '.') + "' within jar '" + jarFileName + "'"+cnfe);
}
return classes;
}
/**
get classes from a root directory which implements an interface.
@param dir the root directory.
@param iface the interface in search.
@return the set of classes in jar implementing the interface.
@throws IOException when there is a file open error.
*/
public static List<Class> getClassesFromDirectory(File dir, Class iface)
{
List<Class> classes = new Vector<>();
FileLister lister = new FileLister(dir);
while(lister.hasMoreElements())
{
File f = lister.nextElement();
String className = f.toString();
//System.err.println(className);
if(className.endsWith(".class") && className.indexOf("$") < 0 )
{
className = className.replace(File.separatorChar,'.');
className = className.substring(0, className.length() - ".class".length());
while(className.charAt(0)=='.') className = className.substring(1);
//System.err.println("\t"+className);
try
{
Class cl = Class.forName(className);
if(iface.isAssignableFrom(cl))
{
//System.err.println("\t"+className+" can be assigned to "+iface);
classes.add(cl);
}
}
catch(ClassNotFoundException cnfe)
{}
}
}
return classes;
}
/**
get classes from the class path which implements an interface.
@param iface the interface in search.
@return the set of classes in jar implementing the interface.
*/
public static List<Class> getAvailableClassesOfInterface(String iface)
{
List<Class> result = null;
try
{
Class iface_class = Class.forName(iface);
result = getAvailableClassesOfInterface(iface_class);
}
catch(ClassNotFoundException cnfe) {}
return result;
}
/**
get classes from the class path which implements an interface.
@param iface the interface in search.
@return the set of classes in jar implementing the interface.
*/
public static List<Class> getAvailableClassesOfInterface(Class iface)
{
String cp = System.getProperty("java.class.path");
//System.out.println("java.class.path = " + cp);
List<Class> result = new Vector<>();
// semicolon (Windows) or colon (Unix) by System.getProperty("path.separator")
String separator = System.getProperty("path.separator");
for(String p : cp.split(separator))
{
File f = new File(p);
if(f.isDirectory())
result.addAll(getClassesFromDirectory(f, iface));
else if(f.isFile() && p.endsWith("jar"))
result.addAll(getClassesFromJARFile(p, iface));
}
HashSet<Class> set = new HashSet<>(result);
result.clear();
for(Class c : set)
{
//System.err.println(c);
result.add(c);
}
return result;
}
/**
InterfaceFinder.java
Search the class path for classes which implement a specific interface
Usage: java -cp jar_file;class_folder;. InterfaceFinder interface_name_to_search
Example:
> javac InterfaceFinder.java
> java -cp rt.jar;. InterfaceFinder java.util.List
class javax.management.relation.RoleUnresolvedList
class java.util.AbstractList
class java.util.SubList
class java.util.concurrent.CopyOnWriteArrayList
class javax.management.AttributeList
class java.util.AbstractSequentialList
class java.util.RandomAccessSubList
class java.util.ArrayList
class java.util.Vector
class java.util.Stack
class java.util.LinkedList
class javax.management.relation.RoleList
interface java.util.List
Note that since JDK 9 there is no rt.jar for testing
*/
public static void main(String args[])
{
String iface = "java.util.List";
if(args.length > 0)
iface = args[0];
List<Class> classes =
getAvailableClassesOfInterface(iface);
for(Class c : classes)
{
System.err.println(c);
}
}
}
2009年5月21日 星期四
interface finder
訂閱:
文章 (Atom)