Java tutorial
/* * 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; }