Reflection Java

/*
 * ReflectClass.java -  Dump a class using Reflection.
 *
 * Copyright (c) 1997 Chuck McManis, All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies.
 *
 * CHUCK MCMANIS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
 * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. CHUCK MCMANIS
 * SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT
 * OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */
import java.lang.reflect.*;
import java.util.*;
public class ReflectClass {
    static String tName(String nm, Hashtable ht) {
        String yy;
        String arr;
        if (nm.charAt(0) != '[') {
            int i = nm.lastIndexOf(".");
            if (i == -1)
                return nm; // It's a primitive type, ignore it.
            else {
                yy = nm.substring(i+1);
                if (ht != null)
                    ht.put(nm, yy); // note class types in the hashtable.
                return yy;
            }
        }
        arr = "[]";
        if (nm.charAt(1) == '[')
            yy = tName(nm.substring(1), ht);
        else {
            switch (nm.charAt(1)) {
                case 'L' :
                    yy = tName(nm.substring(nm.indexOf("L")+1, nm.indexOf(";")), ht);
                    break;
                case 'I':
                    yy = "int";
                    break;
                case 'V':
                    yy = "void";
                    break;
                case 'C':
                    yy = "char";
                    break;
                case 'D':
                    yy = "double";
                    break;
                case 'F':
                    yy = "float";
                    break;
                case 'J':
                    yy = "long";
                    break;
                case 'S':
                    yy = "short";
                    break;
                case 'Z':
                    yy = "boolean";
                    break;
                case 'B':
                    yy = "byte";
                    break;
                default:
                    yy = "BOGUS:"+nm;
                    break;
            }
        }
        return yy+arr;
    }
    public static void main(String args[]) {
        Constructor   cn[];
        Class         cc[];
        Method        mm[];
        Field         ff[];
        Class         c = null;
        Class         supClass;
        String      x, y, s1, s2, s3;
        Hashtable classRef = new Hashtable();
      if (args.length == 0) {
            System.out.println("Please specify a class name on the command line.");
            System.exit(1);
        }
        try {
            c = Class.forName(args[0]);
        } catch (ClassNotFoundException ee) {
            System.out.println("Couldn't find class '"+args[0]+"'");
            System.exit(1);
        }
        /*
         * Step 0: If our name contains dots we're in a package so put
         * that out first.
         */
        x = c.getName();
        if (x.lastIndexOf(".") != -1) {
            y = x.substring(0, x.lastIndexOf("."));
            System.out.println("package "+y+";\n\r");
        }
        /*
         * Let's use the Reflection API to sift through what is
         * inside this class.
         *
         * Step 1: Collect referenced classes
         * This step is used so that I can regenerate the import statements.
         * It isn't strictly required of course, Java works just fine with
         * fully qualified object class names, but it looks better when you
         * use 'String' rather than 'java.lang.String' as the return type.
         */
        ff = c.getDeclaredFields();
        for (int i = 0; i < ff.length; i++) {
            x = tName(ff[i].getType().getName(), classRef);
        }
        cn = c.getDeclaredConstructors();
        for (int i = 0; i < cn.length; i++) {
            Class cx[] = cn[i].getParameterTypes();
            if (cx.length > 0) {
                for (int j = 0; j < cx.length; j++) {
                    x = tName(cx[j].getName(), classRef);
                }
            }
        }
        mm = c.getDeclaredMethods();
        for (int i = 0; i < mm.length; i++) {
            x = tName(mm[i].getReturnType().getName(), classRef);
            Class cx[] = mm[i].getParameterTypes();
            if (cx.length > 0) {
                for (int j = 0; j < cx.length; j++) {
                    x = tName(cx[j].getName(), classRef);
                }
            }
        }
        // Don't import ourselves ...
        classRef.remove(c.getName());
        /*
         * Step 2: Start class description generation, start by printing
         *  out the import statements.
         *
         * This is the line that goes 'public SomeClass extends Foo {'
         */
        for (Enumeration e = classRef.keys(); e.hasMoreElements(); ) {
            System.out.println("import "+e.nextElement()+";");
        }
        System.out.println();
        /*
         * Step 3: Print the class or interface introducer. We use
         * a convienience method in Modifer to print the whole string.
         */
        int mod = c.getModifiers();
        System.out.print(Modifier.toString(mod));
        if (Modifier.isInterface(mod)) {
            System.out.print(" interface ");
        } else {
            System.out.print(" class ");
        }
        System.out.print(tName(c.getName(), null));
        supClass = c.getSuperclass();
        if (supClass != null) {
            System.out.print(" extends "+tName(supClass.getName(), classRef));
        }
        System.out.println(" {");
        /*
         * Step 4: Print out the fields (internal class members) that are declared
         * by this class.
         *
         * Fields are of the form [Modifiers] [Type] [Name] ;
         */
        System.out.println("\n\r/*\n\r * Field Definitions.\r\n */");
        for (int i = 0; i < ff.length; i++) {
            Class ctmp = ff[i].getType();
            int md     = ff[i].getModifiers();
            System.out.println("    "+Modifier.toString(md)+" "+
                    tName(ff[i].getType().getName(), null) +" "+
                    ff[i].getName()+";");
        }
        /*
         * Step 5: Print out the constructor declarations.
         *
         * We note the name of the class which is the 'name' for all
         * constructors. Also there is no type, so the definition is
         * simplye [Modifiers] ClassName ( [ Parameters ] ) { }
         *
         */
        System.out.println("\n\r/*\n\r * Declared Constructors. \n\r */");
        x = tName(c.getName(), null);
        for (int i = 0; i < cn.length; i++) {
            int md = cn[i].getModifiers();
            System.out.print("    " + Modifier.toString(md) + " " + x);
            Class cx[] = cn[i].getParameterTypes();
            System.out.print("( ");
            if (cx.length > 0) {
                for (int j = 0; j < cx.length; j++) {
                    System.out.print(tName(cx[j].getName(), null));
                    if (j < (cx.length - 1)) System.out.print(", ");
                }
            }
            System.out.print(") ");
            System.out.println("{ ... }");
        }
        /*
         * Step 6: Print out the method declarations.
         *
         * Now methods have a name, a return type, and an optional
         * set of parameters so they are :
         *  [modifiers] [type] [name] ( [optional parameters] ) { }
         */
        System.out.println("\n\r/*\n\r * Declared Methods.\n\r */");
        for (int i = 0; i < mm.length; i++) {
            int md = mm[i].getModifiers();
            System.out.print("    "+Modifier.toString(md)+" "+
                    tName(mm[i].getReturnType().getName(), null)+" "+
                    mm[i].getName());
            Class cx[] = mm[i].getParameterTypes();
            System.out.print("( ");
            if (cx.length > 0) {
                for (int j = 0; j < cx.length; j++) {
                    System.out.print(tName(cx[j].getName(), classRef));
                    if (j < (cx.length - 1)) System.out.print(", ");
                }
            }
            System.out.print(") ");
            System.out.println("{ ... }");
        }
        /*
         * Step 7: Print out the closing brace and we're done!
         */
        System.out.println("}");
    }
}