Project 1: Java Package Database Creation

Due Wednesday, October 15, 5pm

ClassReader is a Java application that, when given a .class file, will output via the command line its contents.  It will display information on package names, class names, interfaces, methods, method signatures, etc.  Your first task is to install ClassReader, read its documentation, and understand how it works.  Note that you can access ClassReader programmatically, so that you don't have to translate its text output into a form that you can manipulate in Java.

In class, we created an ER diagram of the contents of a Java file, and the relations that comprise this diagram.  A modified version of this diagram that is suitable for this project is shown below:

 

Constraints associated with this model are:

In the following, PNAME is the name of a Package, TNAME is the name of a Class or Interface, ClassNAME is the name of a Class, InterfaceNAME is the name of an interface, MNAME is the name of a member (Field or Method).  "Subscripts" like PNAME1 are used to differentiate different package names.

And a set of relations that define its contents are:

Package( PNAME1, PNAME2 )
-- PNAME1 is a subpackage of PNAME2
-- a tuple might be ('java.util.concurrent', 'java.util')
-- note that package names are always fully qualified

Type( PNAME, TNAME, visibility, static, abstract, ttype )
-- a tuple might be ('java.util', 'BitSet', 'public',
-- 0 /*not static*/, 0 /*not abstract*/, 'class')

Implements( ClassNAME, InterfaceNAME )
-- where ClassName is (PNAME, TNAME) pair. Same for InterfaceName.
-- a tuple might be ('java.util', 'BitSet', 'java.io', 'Serializable')

Extends( superNAME, subNAME
-- where superName is (PNAME, TNAME).  same for subNAME.
-- a tuple might be ('java.util', 'BitSet', 'java.lang', 'Object')

Member( PNAME, TNAME, NAME, visibility, static, abstract, mtype, PNAME0, TNAME0, arraydepth )
-- example int java.util.BitSet.length() is expressed by
-- tuple might be ('java.util', 'BitSet', 'length', 
-- 'public', 0 /*not static*/, 0 /*not abstract*/, 'method', 'java.primitive', 'void', 0 )

Parameter(PNAME1, TNAME1, NAME, PNAME2, TNAME2 arraydepth, number )
-- (PNAME1, TNAME1, NAME) identifies a member of a class or interface
-- (PNAME2, TNAME2) identifies the *type* of this member
-- arraydepth is the depth of arrays for the member type
-- and number is the # of the parameter for this member.
-- consider void java.util.BitSet.intersects(BitSet set)
-- a tuple might be ('java.util', 'BitSet', 'intersects', 'java.util', 'BitSet', 0, 1 )

create view TypedElement as
     (select PNAME, TNAME, NAME, 'param' as etype, arrayDepth from Parameter) 
     union
     (select PNAME, TNAME, NAME, 'member' as etype, arrayDepth from Member)

References( memberNAME, refedMemberName )
-- memberName is (PNAME, TNAME, NAME) triple.
-- same for refedMemberName.

In this project, you are to:

Example


Here is a java program:
class t {
   public static void main(String args[]) {
      boolean t1 = "string" instanceof String;
      System.out.println(t1);
      int i[] = {4};
      boolean t2 = i instanceof int[];
      System.out.println(t2);
   }
}

Here is an excerpt of ClassReader's output:

package:

class name:
t
modifiers:
super class: java.lang.Object
super interfaces: null
method:
  name:<init>
  modifiers:
  return type: void
  argument types: null
  reference table:
     MethodRefer: java.lang.Object: void <init>()

   name: main
   modifiers: Public, Static
   return type:void
   argument types: java.lang.String[]
   reference table:
     FieldRefer: java.lang.System: java.io.PrintStream out
     MethodRefer: java.io.PrintStream: void println(boolean)
     FieldRefer: java.lang.System: java.io.PrintStream out
     MethodRefer: java.io.PrintStream: void println(boolean)

fields:

The tuples that you should insert are:

insert into packages ('default', null); 
-- 'default' is the default name for an unnamed package

insert into type( 'default', 't', 'public', 0, 0, 'class');
-- 'public',0,0 means public, static, abstract 1=true & 0=false

insert into extends( 'java.lang', 'Object', 'default', 't');
-- default.t extends java.lang.Object

insert into type('java.primitives', 'void', 'public', 0, 0, 'primitive'); 
-- our way of defining a primitive type "void"

insert into members( 'default', 't', '<init>', 'public', 1, 0, 'method', '
java.primitives', 'void', 0);
    -- the public static <init> method returns type void

insert into References( 'default', 't', '<init>', '
java.lang', 'Object', '<init>' );
    -- and references the method <init> in java.lang.Object


insert into members( 'default', 't', 'main', 'public', 1, 0, 'method', 'java.primitives', 'void', 0);
   -- main method is visible and
   -- static (1), and returns java.primitives.void result
insert into parameters( 'default', 't', 'main', 'java.lang', 'String', 1, 1);
   -- first parameter of main is java.lang.String[] (1,1 means arraydepth=1, parameter#=1)
insert into References( 'default', 't', 'main', 'java.io', 'PrintStream', 'out');
   -- member default.t.main references member
   -- java.io.Printstream.out
-- note: the second reference produced by ClassReader will cause an insertion
-- of an identical tuple into References.  By defining your References table with
-- keys, inserting a duplicate tuple will be rejected (but this is OK).

insert into References( 'default', 't', 'main', 'java.io', 'PrintStream', 'println');
...

I would suggest that you immediately populate the type table with known java primitives before loading any class-file-specific tuples.

What to Submit

Write a program that takes any number of class files as input, runs ClassReader on each file, and inserts tuples into your database for each file:

  
 > java MyProgram *.class

will add tuples to your database for each class file in the current directory.  In general, your program will take as input a list of class files. In general, the command line for MyProgram or whatever you will call it is:

> java MyProgram [-i] classfile1 ... classfilen

where the -i option initializes the database (by deleting any existing tuples).

You will need to submit the following: