CIT 597 Assignment 4: Class Spy
Fall 2003, David Matuszek

Purpose of the assignment:

Idea of the assignment:

Use Java Reflection to reconstruct, as fully as possible, the source code of a Java class from its Class object.

Details:

Write a class Spy with at least the following methods:

void print(Class c)
Given a class c, reconstructs the source code as completely as possible, and prints it on System.out.
void print(Class c, PrintStream p)
Given a class c, reconstructs the source code as completely as possible, and prints it on the given PrintStream p. (Note: System.out is an object of class PrintStream.)

You can, if you wish, have a main method for testing purposes. You can (and should) have a lot of other methods, as well.

I'm not entirely sure myself how much information can be recovered. I know it's possible to collect information about classes, interfaces, public fields, constructors, methods, and parameters; I don't yet know about things like class (static) variables. Part of your task is to browse the API (particularly java.lang.Class and java.lang.reflect.*) to find out just how much can be done.

Output:

Your goals are to reconstruct a class as fully as possible, and to produce output that looks like a Java program and can be compiled. (If you run it, it won't do anything, because all the methods and constructors will have empty bodies; but you should be able to compile it.) It should also have reasonable indentation. For example, the output for a (very small) class might look something like this:

public class FooBar {
    public String hello;
    public static void main(String[] args) { }
}

You should make your output as "clean" as possible by trimming off all unnecessary qualifications and defaults. Some examples are:

Your output should also contain a comment with your name.

I'll give you extra credit if you can collect import statements to put at the top of your output, and use these to trim off qualifications that would otherwise be needed.

Suggestions:

Here are some things that can get in the way of being able to compile your result, and some suggestions about what to do about them.

The file name must match the name of the class.
For output to System.out, this doesn't matter--it's just going to the screen anyway. Otherwise, the best thing to do is probably to ignore the problem, and make the user rename the file later. You can't save it on a file named className.java, because you probably already have such a file in the same directory.
The class extends another user-defined class.
If you wish, you can print out the other class as well. Otherwise, your output can be compiled if a compiled version of the other class is available.
You can have only one public class on a file.
For public classes other than the one given as a parameter, you can indicate this as
     // public
     class TheOtherClass { ... }

There are other cases where it will be difficult or impossible to create compilable output. The goal in such cases is to find relatively simple workarounds. Remember the 90/90 rule of programming: The first 90% of the program takes the first 90% of the effort, and the remaining 10% of the program takes the remaining 90% of the effort. That is, your program should usually produce output that can be compiled. If your output cannot be compiled for one reason or another, and it's simple to fix, fix it; but if it would take a lot of work, then don't bother.

Due date:

Wednesday, October 8, before midnight. Turn in a zipped set of files via Blackboard.