2009年5月21日 星期四

interface finder

  1.  
  2. /*
  3. * @(#)InterfaceFinder.java v0.8, 2009/05/06-2020/2/8
  4. *
  5. * Search the class path for classes which implement a specific interface
  6. *
  7. * Usage: java -cp jar_file;class_folder;. InterfaceFinder interface_name_to_search
  8. */
  9.  
  10. import java.util.Enumeration;
  11. import java.util.List;
  12. import java.util.Vector;
  13. import java.util.Stack;
  14. import java.util.HashSet;
  15. import java.util.jar.JarEntry;
  16. import java.util.jar.JarInputStream;
  17. import java.io.File;
  18. import java.io.FileInputStream;
  19. import java.io.IOException;
  20.  
  21. /**
  22. The interface finder is used to find all classes
  23. implementing a specific interface.
  24. The location in search includes all the subdirectories
  25. in the class path. Typical usage is as follows.
  26.  
  27. List<Class> InterfaceFinder.getAvailableInterfaces("java.util.List");
  28.  
  29. * @since 0.8
  30. * @version 0.8, 2009/05/06-2020/2/8
  31. * @author Seke Wei
  32. */
  33. public class InterfaceFinder
  34. {
  35. public static final String version="InterfaceFinder.java v0.8 2020/02/08";
  36.  
  37. /**
  38. a file lister which uses the depth first strategy
  39. to traverse all files under a given directory.
  40. */
  41. public static class FileLister implements Enumeration
  42. {
  43. boolean hasMore;
  44. Stack<File> fstack;
  45.  
  46. /**
  47. constructor for file lister.
  48. @param dir the root directory for search.
  49. */
  50. public FileLister(File dir)
  51. {
  52. fstack = new Stack<>();
  53. if(dir.isDirectory())
  54. fstack.push(dir);
  55. hasMore = true;
  56. }
  57.  
  58. /**
  59. check if there is still file available for listing.
  60. @return true for elements available and false for otherwise.
  61. */
  62. public boolean hasMoreElements()
  63. {
  64. return hasMore;
  65. }
  66.  
  67. /**
  68. get the next available file.
  69. directories are skipped.
  70. @return the file.
  71. */
  72. public File nextElement()
  73. {
  74. File next = null;
  75.  
  76. while(fstack.empty()==false)
  77. {
  78. next = (File) fstack.pop();
  79. if(next.isFile())
  80. break;
  81.  
  82. for(File f : next.listFiles())
  83. fstack.push(f);
  84. }
  85.  
  86. if(fstack.empty()) hasMore=false;
  87.  
  88. return next;
  89. }
  90. }
  91.  
  92. /**
  93. get classes from a jar file which implements an interface.
  94. @param jarFileName the jar filename.
  95. @param iface the interface in search.
  96. @return the set of classes in jar implementing the interface.
  97. */
  98. public static List<Class> getClassesFromJARFile(String jarFileName, Class iface)
  99. {
  100. final List<Class> classes = new Vector<>();
  101. JarInputStream jarFile = null;
  102. String className = "";
  103. try
  104. {
  105. jarFile = new JarInputStream(new FileInputStream(jarFileName));
  106. JarEntry jarEntry;
  107. while(true)
  108. {
  109. jarEntry = jarFile.getNextJarEntry();
  110. if(jarEntry == null) break;
  111.  
  112. className = jarEntry.toString();
  113.  
  114. //System.err.println(className);
  115.  
  116. if(className.endsWith(".class") && className.indexOf("$") < 0 )
  117. {
  118. //extractClassFromJar(jar, packageName, classes, jarEntry)
  119. className = className.replace('/','.');
  120. className = className.substring(0, className.length() - ".class".length());
  121. Class cl = Class.forName(className);
  122. if(iface.isAssignableFrom(cl))
  123. {
  124. //System.err.println("\t"+className+" can be assigned to "+iface);
  125. classes.add(cl);
  126. }
  127. }
  128. }
  129. jarFile.close();
  130. }
  131. catch (IOException ioe)
  132. {
  133. System.err.println("Unable to get Jar input stream from '"+jarFileName+"'"+ioe);
  134. }
  135. catch (ClassNotFoundException cnfe)
  136. {
  137. System.err.println("unable to find class named " + className.replace('/', '.') + "' within jar '" + jarFileName + "'"+cnfe);
  138. }
  139.  
  140. return classes;
  141. }
  142.  
  143. /**
  144. get classes from a root directory which implements an interface.
  145. @param dir the root directory.
  146. @param iface the interface in search.
  147. @return the set of classes in jar implementing the interface.
  148. @throws IOException when there is a file open error.
  149. */
  150. public static List<Class> getClassesFromDirectory(File dir, Class iface)
  151. {
  152. List<Class> classes = new Vector<>();
  153.  
  154. FileLister lister = new FileLister(dir);
  155. while(lister.hasMoreElements())
  156. {
  157. File f = lister.nextElement();
  158. String className = f.toString();
  159.  
  160. //System.err.println(className);
  161.  
  162. if(className.endsWith(".class") && className.indexOf("$") < 0 )
  163. {
  164. className = className.replace(File.separatorChar,'.');
  165. className = className.substring(0, className.length() - ".class".length());
  166. while(className.charAt(0)=='.') className = className.substring(1);
  167. //System.err.println("\t"+className);
  168.  
  169. try
  170. {
  171. Class cl = Class.forName(className);
  172. if(iface.isAssignableFrom(cl))
  173. {
  174. //System.err.println("\t"+className+" can be assigned to "+iface);
  175. classes.add(cl);
  176. }
  177. }
  178. catch(ClassNotFoundException cnfe)
  179. {}
  180. }
  181. }
  182.  
  183. return classes;
  184. }
  185.  
  186. /**
  187. get classes from the class path which implements an interface.
  188. @param iface the interface in search.
  189. @return the set of classes in jar implementing the interface.
  190. */
  191. public static List<Class> getAvailableClassesOfInterface(String iface)
  192. {
  193. List<Class> result = null;
  194.  
  195. try
  196. {
  197. Class iface_class = Class.forName(iface);
  198. result = getAvailableClassesOfInterface(iface_class);
  199. }
  200. catch(ClassNotFoundException cnfe) {}
  201.  
  202. return result;
  203. }
  204.  
  205. /**
  206. get classes from the class path which implements an interface.
  207. @param iface the interface in search.
  208. @return the set of classes in jar implementing the interface.
  209. */
  210. public static List<Class> getAvailableClassesOfInterface(Class iface)
  211. {
  212. String cp = System.getProperty("java.class.path");
  213. //System.out.println("java.class.path = " + cp);
  214.  
  215. List<Class> result = new Vector<>();
  216.  
  217. // semicolon (Windows) or colon (Unix) by System.getProperty("path.separator")
  218. String separator = System.getProperty("path.separator");
  219. for(String p : cp.split(separator))
  220. {
  221. File f = new File(p);
  222. if(f.isDirectory())
  223. result.addAll(getClassesFromDirectory(f, iface));
  224. else if(f.isFile() && p.endsWith("jar"))
  225. result.addAll(getClassesFromJARFile(p, iface));
  226. }
  227.  
  228. HashSet<Class> set = new HashSet<>(result);
  229.  
  230. result.clear();
  231.  
  232. for(Class c : set)
  233. {
  234. //System.err.println(c);
  235. result.add(c);
  236. }
  237.  
  238. return result;
  239. }
  240.  
  241. /**
  242. InterfaceFinder.java
  243. Search the class path for classes which implement a specific interface
  244.  
  245. Usage: java -cp jar_file;class_folder;. InterfaceFinder interface_name_to_search
  246.  
  247. Example:
  248. > javac InterfaceFinder.java
  249. > java -cp rt.jar;. InterfaceFinder java.util.List
  250. class javax.management.relation.RoleUnresolvedList
  251. class java.util.AbstractList
  252. class java.util.SubList
  253. class java.util.concurrent.CopyOnWriteArrayList
  254. class javax.management.AttributeList
  255. class java.util.AbstractSequentialList
  256. class java.util.RandomAccessSubList
  257. class java.util.ArrayList
  258. class java.util.Vector
  259. class java.util.Stack
  260. class java.util.LinkedList
  261. class javax.management.relation.RoleList
  262. interface java.util.List
  263.  
  264. Note that since JDK 9 there is no rt.jar for testing
  265. */
  266. public static void main(String args[])
  267. {
  268. String iface = "java.util.List";
  269. if(args.length > 0)
  270. iface = args[0];
  271.  
  272. List<Class> classes =
  273. getAvailableClassesOfInterface(iface);
  274.  
  275. for(Class c : classes)
  276. {
  277. System.err.println(c);
  278. }
  279. }
  280. }