FileDocCategorySizeDatePackage
ClassInfo.javaAPI DocExample14735Thu May 30 21:16:12 BST 2002com.ronsoft.books.nio.appendix

ClassInfo

public class ClassInfo extends Object
Extract information about a class. This class was used to generate the quick reference for the NIO book for O'Reilly. It's kind of ugly and there are a lot of hacks in here. The most obvious one is the wrapping of tags around class and member names in the toString() output. With a little work this could be made into a generic class introspector, but it currently has some warts on it. Created May 2002
author
Ron Hitchens (ron@ronsoft.com)
version
$Id: ClassInfo.java,v 1.2 2002/05/31 04:16:13 ron Exp $

Fields Summary
private static final String
SRC_DIR
private Package
packg
private Class
thisClass
private Class
superClass
private Class
declaringClass
private Class[]
interfaces
private Field[]
fields
private Constructor[]
constructors
private Method[]
methods
private Class[]
classes
private ClassInfo[]
internalClasses
private int
mods
private Comper
comper
private String[]
zeroStringArray
Constructors Summary
public ClassInfo(String className)


	   
		 
	
		this (Class.forName (className));
	
public ClassInfo(String className, boolean prot)

		this (Class.forName (className),
			(prot) ? Modifier.PUBLIC | Modifier.PROTECTED : Modifier.PUBLIC);
	
public ClassInfo(Class clas)

		this (clas, Modifier.PUBLIC);
	
public ClassInfo(Class clas, int mods)

		thisClass = clas;
		packg = clas.getPackage();
		superClass = clas.getSuperclass();
		interfaces = clas.getInterfaces();
		declaringClass = clas.getDeclaringClass();
		fields = trimFields (clas.getDeclaredFields(), mods);
		constructors = trimConstructors (clas.getConstructors(), mods);
		methods = trimMethods (clas.getDeclaredMethods(), mods);
		classes = trimClasses (clas.getDeclaredClasses(), mods);

		if (classes.length == 0) {
			internalClasses = new ClassInfo [0];
		} else {
			List list = new LinkedList();

			for (int i = 0; i < classes.length; i++) {
				list.add (new ClassInfo (classes [i]));
			}

			internalClasses = new ClassInfo [list.size()];
			list.toArray (internalClasses);
		}
	
Methods Summary
private voidappendRegexType(java.lang.StringBuffer sb, java.lang.Class t)

		if (t.isArray()) {
			sb.append (getSimpleClassName (t.getComponentType()));
			sb.append ("\\s*\\[\\]\\s*");
		} else {
			sb.append (getSimpleClassName (t));
		}

	
private java.lang.String[]getArgNames(java.lang.reflect.Member member, java.lang.Class[] params)


	        
	
		if (params.length == 0) {
			return (zeroStringArray);
		}

		CharSequence cs = null;

		try {
			// This is inefficient, the file is loaded for
			// each constructor/method.  The source file should
			// be loaded in the constructor and re-used.
			cs = loadFile (srcFileName (thisClass.getName()));
		} catch (Exception e) {
			System.out.println ("Can't open file: " + e);
			return (null);
		}

		boolean isMethod = (member instanceof Method);
		StringBuffer sb = new StringBuffer();
		String s;

		sb.append ("(?ms)^\\s*");

		s = getModifierNames (member.getModifiers());
		sb.append (s.replaceAll ("\\s+", "\\\\s+"));
		sb.append ("\\s+");

		if (isMethod) {
			Method method = (Method) member;

			appendRegexType (sb, method.getReturnType());

			sb.append ("\\s+");
		}

		sb.append (getSimpleClassName (member.getName()));

		sb.append ("\\s*\\(");

		for (int i = 0; i < params.length; i++) {
			if (i != 0) {
				sb.append (",\\s*");
			}
			sb.append ("\\s*\\w*?\\s*");

			Class p = params [i];

			appendRegexType (sb, p);

			sb.append ("\\s+");
			sb.append ("(\\w+)\\s*");
		}

		sb.append ("\\)");

		String regex = sb.toString();
		Pattern pat = Pattern.compile (regex);
		Matcher matcher = pat.matcher (cs);

		if ( ! matcher.find()) {
			System.out.println (getSimpleClassName (thisClass) + ": no match='" + regex + "'");
			return (null);
		}

		int count = matcher.groupCount();
		String [] names = new String [count];

		for (int i = 0; i < count; i++) {
			names [i] = matcher.group (i + 1);
		}

		return (names);
	
public java.lang.StringgetClassName(java.lang.String name)

		String pkgname = packg.getName();

		if (name.startsWith ("java.lang")) {
			return (name.substring ("java.lang".length() + 1));
		}

		if (name.startsWith (pkgname)) {
			String simple = name.substring (pkgname.length() + 1);

			// is the package name the whole prefix?
			if (simple.indexOf (".") == -1) {
				return (simple.replace ('$", '."));
			}
		}

		return (name.replace ('$", '."));
	
public java.lang.StringgetClassName(java.lang.Class clas)

		return (getClassName (clas.getName()));
	
public java.lang.StringgetClassName()

		return (getClassName (thisClass));
	
public java.lang.StringgetModifierNames(int mods)

		if (thisClass.isInterface()) {
			mods &= ~Modifier.ABSTRACT;
		}

		return (Modifier.toString (mods));
	
public java.lang.StringgetModifierNames()

		return (getModifierNames (thisClass.getModifiers()));
	
public java.lang.StringgetSimpleClassName(java.lang.String name)

		String rep = name.replace ('$", '.");
		int n = rep.lastIndexOf (".");

		if (n == -1) {
			return (rep);
		}

		return (rep.substring (n + 1));
	
public java.lang.StringgetSimpleClassName(java.lang.Class clas)

		return (getSimpleClassName (clas.getName()));
	
public java.lang.ClassgetSuperClass()

		if ((superClass == null) || (superClass == Object.class)) {
			return (null);
		}

		return (superClass);
	
private voidindent(java.lang.StringBuffer sb, java.lang.String indent, int level)

		for (int i = 0; i < level; i++) {
			sb.append (indent);
		}
	
public booleanisInterface()

		return (thisClass.isInterface());
	
private java.lang.CharSequenceloadFile(java.lang.String name)

		BufferedReader in = new BufferedReader (new FileReader (name));
		StringBuffer sb = new StringBuffer();
		String s;

		while ((s = in.readLine()) != null) {
			sb.append (s);
			sb.append ("\n");
		}

		in.close();

		return sb;
	
public static voidmain(java.lang.String[] argv)

		for (int i = 0; i < argv.length; i++) {
			ClassInfo ci = new ClassInfo (argv [i]);

			System.out.println (new ClassInfo (argv [i]).toString());
		}
	
private voidprintArgs(java.lang.StringBuffer sb, java.lang.reflect.Member member)

		Class [] paramTypes = null;

		if (member instanceof Constructor) {
			Constructor c = (Constructor) member;
			paramTypes = c.getParameterTypes();
		}

		if (member instanceof Method) {
			Method m = (Method) member;
			paramTypes = m.getParameterTypes();
		}

		if ((paramTypes == null) || (paramTypes.length == 0)) {
			sb.append ("()");
			return;
		}

		sb.append (" (");

		String [] names = getArgNames (member, paramTypes);

		for (int i = 0; i < paramTypes.length; i++) {
			Class p = paramTypes [i];

			if (i != 0) {
				sb.append (", ");
			}

			printType (sb, p);

			if (names == null) {
				sb.append (" XXX");
			} else {
				sb.append (" ").append (names [i]);
			}
		}

		sb.append (")");
	
private voidprintExcept(java.lang.StringBuffer sb, java.lang.reflect.Member member, java.lang.String indent, int indentLevel)

		Class [] exs = null;

		if (member instanceof Constructor) {
			exs = ((Constructor) member).getExceptionTypes();
		}

		if (member instanceof Method) {
			exs = ((Method) member).getExceptionTypes();
		}

		if (exs.length == 0) {
			return;
		}

		sb.append ("\n");
		indent (sb, indent, indentLevel + 1);
		sb.append ("throws ");

		for (int i = 0; i < exs.length; i++) {
			if (i != 0) {
				sb.append (", ");
			}

			sb.append (getClassName (exs [i]));
		}
	
private voidprintMembers(java.lang.StringBuffer sb, java.lang.reflect.Member[] members, java.lang.String indent, int indentLevel)

		for (int i = 0; i < members.length; i++) {
			Member member = members [i];
			int mods = member.getModifiers();

			if (Modifier.isPrivate (mods)) {
				continue;
			}

			if (( ! Modifier.isPublic (mods)) &&
				(! Modifier.isProtected (mods)))
			{
				continue;	// package private
			}

			indent (sb, indent, indentLevel);
			sb.append (getModifierNames (mods));

			if (member instanceof Field) {
				Field field = (Field) member;

				sb.append (" ");
				printType (sb, field.getType());
			}

			if (member instanceof Method) {
				Method method = (Method) member;

				sb.append (" ");
				printType (sb, method.getReturnType());
			}

			sb.append (" ");
			sb.append ("<emphasis>");
			sb.append (getClassName (member.getName()));
			sb.append ("</emphasis>");

			if ((member instanceof Constructor) ||
				(member instanceof Method))
			{
				printArgs (sb, member);
				printExcept (sb, member, indent, indentLevel);
			}

			if (Modifier.isAbstract (mods)) {
				sb.append (";");
			}

			sb.append ("\n");
		}
	
private voidprintType(java.lang.StringBuffer sb, java.lang.Class type)

		if (type.isArray()) {
			sb.append (getClassName (type.getComponentType()));
			sb.append (" []");
		} else {
			sb.append (getClassName (type));
		}
	
private java.lang.StringsrcFileName(java.lang.String className)

		return (SRC_DIR + "/" + className.replaceAll ("\\.", "/") + ".java");
	
voidstringify(java.lang.StringBuffer sb, java.lang.String indent, int indentLevel, boolean listPackage)

		if (listPackage) {
			indent (sb, indent, indentLevel);
			sb.append ("package ").append (packg.getName());
			sb.append ("\n\n");
		}

		indent (sb, indent, indentLevel);
		sb.append (getModifierNames());

		if (thisClass.isInterface()) {
			sb.append (" ");
		} else {
			sb.append (" class ");
		}

		// HACK!  This should be better parameterized
		sb.append ("<emphasis>");
		sb.append (getClassName());
		sb.append ("</emphasis>");

		Class sc = getSuperClass();

		if (sc != null) {
			sb.append ("\n");
			indent (sb, indent, indentLevel);
			sb.append (indent).append ("extends ");
			sb.append (getClassName (sc));
		}

		if (interfaces.length > 0) {
			sb.append ("\n");
			indent (sb, indent, indentLevel);

			sb.append (indent);

			if (isInterface()) {
				sb.append ("extends ");
			} else {
				sb.append ("implements ");
			}

			for (int i = 0; i < interfaces.length; i++) {
				if (i != 0) {
					sb.append (", ");
				}

				sb.append (getClassName (interfaces [i]));
			}
		}

		sb.append ("\n");
		indent (sb, indent, indentLevel);
		sb.append ("{");
		sb.append ("\n");

		boolean needsep = false;

		if (fields.length > 0) {
			printMembers (sb, fields, indent, indentLevel + 1);
			needsep = true;
		}

		if (constructors.length > 0) {
			if (needsep) sb.append ("\n");
			printMembers (sb, constructors, indent, indentLevel + 1);
			needsep = true;
		}

		if (methods.length > 0) {
			if (needsep) sb.append ("\n");
			printMembers (sb, methods, indent, indentLevel + 1);
			needsep = true;
		}

		if (internalClasses.length > 0) {
			if (needsep) sb.append ("\n");

			for (int i = 0; i < internalClasses.length; i++) {
				if ( ! Modifier.isPublic (classes [i].getModifiers())) {
					continue;
				}

				if (i != 0) sb.append ("\n");

				internalClasses [i].stringify (sb, indent, indentLevel + 1, false);
				// nl is suppressed at end of classes
				sb.append ("\n");
			}
		}

		indent (sb, indent, indentLevel);
		sb.append ("}");
	
public java.lang.StringtoString()

		return (toString ("\t"));
	
public java.lang.StringtoString(java.lang.String indent)

		return (toString (indent, true));
	
public java.lang.StringtoString(java.lang.String indent, boolean listPackage)

		StringBuffer sb = new StringBuffer();

		stringify (sb, indent, 0, listPackage);

		return (sb.toString());
	
private java.lang.Class[]trimClasses(java.lang.Class[] item, int mods)

		List list = new LinkedList();

		for (int i = 0; i < item.length; i++) {
			if ((item [i].getModifiers() & mods) != 0) {
				list.add (item [i]);
			}
		}

		Class [] trimmed = new Class [list.size()];

		list.toArray (trimmed);
		Arrays.sort (trimmed, comper);

		return (trimmed);
	
private java.lang.reflect.Constructor[]trimConstructors(java.lang.reflect.Constructor[] item, int mods)

		List list = new LinkedList();

		for (int i = 0; i < item.length; i++) {
			if ((item [i].getModifiers() & mods) != 0) {
				list.add (item [i]);
			}
		}

		Constructor [] trimmed = new Constructor [list.size()];

		list.toArray (trimmed);
		Arrays.sort (trimmed, comper);

		return (trimmed);
	
private java.lang.reflect.Field[]trimFields(java.lang.reflect.Field[] item, int mods)

		List list = new LinkedList();

		for (int i = 0; i < item.length; i++) {
			if ((item [i].getModifiers() & mods) != 0) {
				list.add (item [i]);
			}
		}

		Field [] trimmed = new Field [list.size()];

		list.toArray (trimmed);
		Arrays.sort (trimmed, comper);

		return (trimmed);
	
private java.lang.reflect.Method[]trimMethods(java.lang.reflect.Method[] item, int mods)

		List list = new LinkedList();

		for (int i = 0; i < item.length; i++) {
			if ((item [i].getModifiers() & mods) != 0) {
				list.add (item [i]);
			}
		}

		Method [] trimmed = new Method [list.size()];

		list.toArray (trimmed);
		Arrays.sort (trimmed, comper);

		return (trimmed);