Java Reflection and a T2M Tool

HINT -- Follow this link for Help getting Started on this assignment

Many tools, especially IDEs, query the contents of .class files to determine a class's methods, fields, and constructors.  In this assignment, you will write a Java program that uses Java Reflection to produce a database of the names of classes and their public non-static and public static members for all classes in a package.  In MDE, mapping from Java .class files to a database is called a Text-2-Model (T2M) tool.

You may work alone or in groups of two.  Start this assignment by reading the course web page on JUnit testing.


The Assignment Big Picture

Write an application with the following command-line invocation:

> java introspect.Main <directory-of-classfiles>
where  directory-of-classfiles is the absolute path to a directory containing class files of a Java package. Here's an example call:
> java introspect.Main  /java/otherclasses/p1package
The output of  introspect.Main  goes to System.out.  If you want to produce a file from the command line, use redirection:
> java introspect.Main /java/otherclasses/p1package > p1package.prog1.pl

Java Reflection

Your program will retrieve the names of all .class files in the given directory and use class reflection to examine the contents of each class file. The key Java statement to inspect a .class file is:

Class<?> c = Class.forName("qualifiedPackageName.className"); 

where c is a Java object from which you can extract the desired structural information and "qualifiedPackageName" is exactly that -- the qualified name of a Java class that is on your classpath (e.g., "java.util.Stack").  You must read JDK documents on the Class class (click here for more details) and the way Java encodes type names (click here for more details). Finding the names of public fields and methods using reflection is simple, once you have the Class<?> object for a given class.

Remember: to introspect a class in this assignment means that it MUST be accessible via your class path AND it is not in a JAR file or zip file.  I will give you zip or jar files for you to test your program.  For your program to work, you will have to unzip/unjar it in a directory that is on your classpath.

Here are key limitations for this assignment to make your life easier:

Note: static methods are methods of a class.  Constructors are methods of a class. So by (my) definition, constructors are static methods even if reflection suggests otherwise.

The goal of this assignment is not to make this a complete tool, but rather to give you an idea of what reflective programs like this can do and how they work.  You can always ask for clarifications.


MDELite Databases and Tables

You will use and install MDELite.  It allows you to create database tables and populate these tables with rows (called tuples).Here's the  MDELite schema of a 2 table database called prog1:
dbase(prog1,[bcClass,bcMember]).

table(bcClass,[cid,"name","superName"]).
table(bcMember,[mid,cid,static,"type","sig"]).

Here's what the above means:

I provide you with a package with a single class, p1package.ReflectionTest.  When you run your program on its directory (where /mydata/blahblah/p1package is this directory) and you have compiled ReflectionTest so that the directory has .class files:

> java introspect.Main /mydata/blahblah/p1package
Your program will output a database  that will match this:

dbase(prog1,[bcClass,bcMember]).

table(bcClass,[cid,"name","superName"]).
bcClass(c10,'p1package.ReflectionTest','Object').

table(bcMember,[mid,cid,static,"type","sig"]).
bcMember(m10,c10,true,'p1package.ReflectionTest','ReflectionTest(int,int,int)').
bcMember(m11,c10,false,'double','d0').
bcMember(m12,c10,false,'double[]','d1').
bcMember(m13,c10,false,'double[][]','d2').
bcMember(m14,c10,false,'double[][][]','d3').
bcMember(m15,c10,true,'int','i1').
bcMember(m16,c10,true,'void','main(String[])').
bcMember(m17,c10,false,'String[][]','test(int[])').
bcMember(m18,c10,true,'void','main2(String[])').
bcMember(m19,c10,false,'String[]','testr(char[],byte[],short[],float[],boolean[],double[][],String[][])').


Note: Before I print out the type names of variables, I shorten "java.lang.X" to "X".  Example: "java.lang.String" is shortened to "String".

Now, you may be wondering why not use Java print statements to produce this same output, as opposed to using a package to create database tuples and print database tables.  The reason is that there is a LOT of hacking to make printed output match a textual standard.  By focusing on creating the right database tuples, the details of creating your own intermediate data structure to store data and then print it are removed.  You win if you use database tables to input and output databases in future assignments, which I assure you, you will be doing.

I have given you enough starter code to allow you to use MDELite without reading its documentation, even though it comes with documentation.  By the time you get this assignment, we should have covered some MDELite basics in class.

Where to Start

I give you the shell of a Netbeans file for you to complete.  It lays out a logical program design that you should understand and follow. Read all 3 classes I provide you, Main.java, Helper.java, and HarvestByteCodes.java.  You will see that I have gutted key methods.  You need to fill them in. I have also provided unit tests for you to verify that your output is correct.  Use them, and add to them files that you use to debug your program.

What to Submit to Canvas

A zip file with all source code (including your Netbeans or Eclipse Project).  The zip file must unzip into <yourLastName>/<YourFilesAndDirectories>  if you work alone or <LastName1-LastName2>/<YourFilesAndDirectories> if you work in a group.

  1. Your program needs to run correctly on Linux machines, even though you may have developed them on a Mac or Windoze platforms.  The TA will grade your program running on Linux.
  2. The Grader should be able to invoke your program just like "java introspect.Main <directory>" exactly like the above from a command line in the unzipped directory. The Grader will reject any submission where this is not the case.

  3. Your program outputs for the packages in this zip file; a readme.txt file would be useful to show me where your results are.

  4. Use the correct output file, above, as a basis for a JUnit test.  Read the course web page on JUnit testing.  It will help you.

  5. Create other unit tests for your program.

  6. A PDF file (in the required format) that the Grader should read to provide any information that is not obvious.  The contents of the PDF file can be minimal.

You should expect that other packages, known only to the grader, will be used to evaluate your program.

A critical part of any design is clarity and understandability.   Hence, you will be graded on the clarity of your project and its ability to work correctly.  Sloppy code, documentation, or anything that makes grading or understanding your program difficult will cost you points!  Beware, some of these "beauty" points are subjective. 

No late assignments/submissions will be accepted.