Mega Code Archive

 
Categories / Java / Reflection
 

CrossRef prints a cross-reference about all classes named in argv

/*  * Copyright (c) Ian F. Darwin, http://www.darwinsys.com/, 1996-2002.  * All rights reserved. Software written by Ian F. Darwin and others.  * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $  *  * Redistribution and use in source and binary forms, with or without  * modification, are permitted provided that the following conditions  * are met:  * 1. Redistributions of source code must retain the above copyright  *    notice, this list of conditions and the following disclaimer.  * 2. Redistributions in binary form must reproduce the above copyright  *    notice, this list of conditions and the following disclaimer in the  *    documentation and/or other materials provided with the distribution.  *  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  * POSSIBILITY OF SUCH DAMAGE.  *   * Java, the Duke mascot, and all variants of Sun's Java "steaming coffee  * cup" logo are trademarks of Sun Microsystems. Sun's, and James Gosling's,  * pioneering role in inventing and promulgating (and standardizing) the Java   * language and environment is gratefully acknowledged.  *   * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for  * inventing predecessor languages C and C++ is also gratefully acknowledged.  */ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; /**  * CrossRef prints a cross-reference about all classes named in argv.  * For each class, all public fields and methods are listed.  * "Reflectance" is used to look up the information.  *  * It is expected that the output will be post-processed e.g.,  * with sort and awk/perl. Try:    java CrossRef |      uniq | # squeeze out polymorphic forms early     sort | awk '$2=="method" { ... }' > crossref-methods.txt  * The part in "{ ... }" is left as an exercise for the reader. :-(  *  * @author  Ian Darwin, Ian@DarwinSys.com  * @version  $Id: CrossRef.java,v 1.16 2003/04/08 20:01:44 ian Exp $  */ public class CrossRef extends APIFormatter {   /** Simple main program, construct self, process each .ZIP file    * found in CLASSPATH or in argv.    */   public static void main(String[] argv) throws IOException {     CrossRef xref = new CrossRef();     xref.doArgs(argv);   }   /**    * Print the fields and methods of one class.    */   protected void doClass(Class c) {     int i, mods;     startClass(c);     try {       Field[] fields = c.getDeclaredFields();       Arrays.sort(fields, new Comparator() {         public int compare(Object o1, Object o2) {           return ((Field)o1).getName().compareTo(((Field)o2).getName());         }       });       for (i = 0; i < fields.length; i++) {         Field field = (Field)fields[i];         if (!Modifier.isPrivate(field.getModifiers()))           putField(field, c);         // else System.err.println("private field ignored: " + field);       }       Method methods[] = c.getDeclaredMethods();       // Arrays.sort(methods);       for (i = 0; i < methods.length; i++) {         if (!Modifier.isPrivate(methods[i].getModifiers()))           putMethod(methods[i], c);         // else System.err.println("pvt: " + methods[i]);       }     } catch (Exception e) {       e.printStackTrace();     }     endClass();   }   /** put a Field's information to the standard output.  */   protected void putField(Field fld, Class c) {     println(fld.getName() + " field " + c.getName() + " ");   }   /** put a Method's information to the standard output.  */   protected void putMethod(Method method, Class c) {     String methName = method.getName();     println(methName + " method " + c.getName() + " ");   }   /** Print the start of a class. Unused in this version,    * designed to be overridden */   protected void startClass(Class c) {   }   /** Print the end of a class. Unused in this version,    * designed to be overridden */   protected void endClass() {   }   /** Convenience routine, short for System.out.println */   protected final void println(String s) {     System.out.println(s);   } } /**  * <p>  * APIFormatter reads one or more Zip files, gets all entries from each  * and, for each entry that ends in ".class", loads it with Class.forName()  * and hands it off to a doClass(Class c) method declared in a subclass.  * <br/>TODO<br/>  * Use GETOPT to control doingStandardClasses, verbosity level, etc.  * @author  Ian Darwin, Ian@DarwinSys.com  * @version  $Id: APIFormatter.java,v 1.6 2004/03/14 14:00:34 ian Exp $  */ abstract class APIFormatter {   /** True if we are doing classpath, so only do java. and javax. */   protected static boolean doingStandardClasses = true;      protected int doArgs(String[] argv) throws IOException {     /** Counter of fields/methods printed. */     int n = 0;     // TODO: options     // -b - process bootclasspath     // -c - process classpath (default)     // -s - only process "java." and "javax."     if (argv.length == 0) {       // No arguments, look in CLASSPATH       String s = System.getProperty("java.class.path");       //  break apart with path sep.       String pathSep = System.getProperty("path.separator");       StringTokenizer st = new StringTokenizer(s, pathSep);       // Process each zip in classpath       while (st.hasMoreTokens()) {         String thisFile = st.nextToken();         System.err.println("Trying path " + thisFile);         if (thisFile.endsWith(".zip") || thisFile.endsWith(".jar"))           processOneZip(thisFile);       }     } else {       // We have arguments, process them as zip/jar files       // doingStandardClasses = false;       for (int i=0; i<argv.length; i++)         processOneZip(argv[i]);     }     return n;   }   /** For each Zip file, for each entry, xref it */   public void processOneZip(String fileName) throws IOException {       List entries = new ArrayList();       ZipFile zipFile = null;       try {         zipFile = new ZipFile(new File(fileName));       } catch (ZipException zz) {         throw new FileNotFoundException(zz.toString() + fileName);       }       Enumeration all = zipFile.entries();       // Put the entries into the List for sorting...       while (all.hasMoreElements()) {         ZipEntry zipEntry = (ZipEntry)all.nextElement();         entries.add(zipEntry);       }       // Sort the entries (by class name)       // Collections.sort(entries);       // Process all the entries in this zip.       Iterator it = entries.iterator();       while (it.hasNext()) {         ZipEntry zipEntry = (ZipEntry)it.next();         String zipName = zipEntry.getName();         // Ignore package/directory, other odd-ball stuff.         if (zipEntry.isDirectory()) {           continue;         }         // Ignore META-INF stuff         if (zipName.startsWith("META-INF/")) {           continue;         }         // Ignore images, HTML, whatever else we find.         if (!zipName.endsWith(".class")) {           continue;         }         // If doing CLASSPATH, Ignore com.* which are "internal API".       //   if (doingStandardClasses && !zipName.startsWith("java")){       //     continue;       //   }                // Convert the zip file entry name, like         //  java/lang/Math.class         // to a class name like         //  java.lang.Math         String className = zipName.replace('/', '.').           substring(0, zipName.length() - 6);  // 6 for ".class"         // Now get the Class object for it.         Class c = null;         try {           c = Class.forName(className);         } catch (ClassNotFoundException ex) {           System.err.println("Error: " + ex);         }         // Hand it off to the subclass...         doClass(c);       }   }   /** Format the fields and methods of one class, given its name.    */   protected abstract void doClass(Class c) throws IOException; }