/*
* 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("}");
}
}