The Java sources that make up your project or enterprise are a valuable asset. They are a virtual Gold Mine of information just waiting to be tapped. Static source analysis tools are becoming an increasingly important facet supporting nearly all development methodologies including XP and Agile Programming. Now JSIS Tools has released a new API called JSIS that gives Java developers a simple but powerful means of parsing Java sources and resolving names to their declarations.
JSIS is the Semantic Interface Specification for JavaTM technology, a de-facto standard Java API that combines the capabilities of a Java Parser, Java Reflection, and a compilation unit manager in one simple package. The JSIS API provides well defined primitive functionality covering the Java syntax and semantics. Secondary queries layered on top of JSIS provide services for tools in any problem domain.
JSIS extends the semantic capability of Reflection with the syntactic parsing capability of a compiler. The synergistic result is a simple and easy to use API that offers more semantic functionality than Reflection and more element classification and syntactic source location information than a Java parser. Using JSIS, Java programmers can create high quality semantically aware source code analysis and inspection tools for use on their own projects or to promote for commercial sale and profit.
Written in Java, JSIS is“write once, run anywhere”. It seamlessly supports Java 1.2, 1.3.x, and 1.4.
Take a look at the JSIS Javadocs or the JSIS API sources.
Java Sources Are Similar to XML Documents
JSIS works much the same way as the well known DOM and SAX parsing models do for XML. You can view your sources as having a structure similar to XML documents; Java elements each have starting and ending points and are hierarchical. You can select specific elements as you would with a DOM parser, or you can extend a parser handler just like you would do with a SAX event-driven parser.
JSIS lets you access all the elements of your Java sources including compilation units, declarations, names, statements, expressions, comments and tokens. It supports analysis of implicit elements such as inherited members. The exact starting and ending location of each element, line and column numbers define the source span each element occupies.
While JSIS works in tandem with reflection, it goes beyond reflection by providing expressions and statements and resolving all identifiers and qualified names to their declarations. A gateway allows you to get reflection objects from JSIS declarations and construct JSIS declaration objects from reflection objects.
Here is a chart comparing JSIS features with Reflection and other Java parsers.
|
A Herd Of Potential Applications
JSIS supports the creation of nearly any application that requires static semantic and syntactic information about a Java source, program, or environment. The following table illustrates just some of the potential tool applications that can be built using JSIS:
Browsing and Navigation Tools
Refactoring Tools
Code Formatting Tools
Code Restructuring and Source Tools
Coding Style and Compliance Tools
Data Flow Analysis Tools
Cross Reference Tools
Dependency Tree Analysis Tools
Design Tools
Document Generation Tools
Invocation Call Tree Analysis Tools
Language-sensitive Editing Tools
Language Translation Tools
Quality Assessment Tools
Thread Analysis Tools
Test-case Generation and Coverage Analysis Tools
Quality, & Complexity Metrics Tools
Reverse Engineering Tools
Sample Application: Finding Unused Declarations
To illustrate how to use JSIS, several small example applications are included with the API bundle. Take a look at one of them, a program that finds and prints a list of unused declarations including private fields, private methods and constructors, parameters, and local declarations. It illustrates the typical pattern of many JSIS programs:
JSIS program setup, setting reference parsing and setting the source path
Selecting a compilation unit by name from the environment
Syntactic analysis using the JSIS.Parser class to parse only non-token elements
Semantic analysis to resolve the identifier to its declaration name element
Use of java.util classes with JSIS elements to make lists and sets
Release of compilation unit resource
The main method takes to parameters, the unit name and the source path location:
Unused usage: java com.JSISTools.Examples.Unused <compilation_unit_qualified_name> <source_path>
For example: java com.JSISTools.Examples.Unused java.lang.String C:/Java/src
The sources of this sample are presented in a browsable HTML format generated by JTNav, an application built and shipped with JSIS. You can explore the program by clicking on the links of names that resolve to the declarations. Start with the class that has the main method: com.JSISTools.Examples.Unused.
One of the first things to do is get the compilation unit named in the first argument:
compUnit = Environment.compilationUnit(args[0]);
Next at line 64 there is an instantiation of the class com.JSISTools.Examples.UnusedParserHandler that extends com.JSISTools.JSIS.ParserHandler and implements the StartElement method:
UnusedParserHandler handler = new UnusedParserHandler();
Parser
parser = new
Parser(handler);
A new Parser is created and the parse is started:
parser.parse(compUnit, false); // false suppresses parse of tokens
StartElement classifies the elements placing the names of the desired declarations like paramters into a list.
switch
(element.kind())
{
case
Declaration.PARAMETER:
{
declarationNamesList.add(((Declaration)
element).parameterName());
break;
}
Elements that are identifiers are resolved to their declared name:
Name name = ((Expression)
element).referencedName();
Names of declarations that belong to the analyzed compilation unit are added to
a set.
if
(name.enclosingCompilationUnit().equals(currentUnit))
{
referencedNameSet.add((Name)
name);
}
Later, an unusedNamesList is populated by testing which declaration names are not contained in the referencedNamesSet:
for
(int i = 0; i <
declarationNamesList.size(); i++) {
name = (Name)
declarationNamesList.get(i);
if
(!referencedNameSet.contains((Name) declarationNamesList.get(i))) {
unusedNamesList.addLast(name);
}
}
The list is sent to Standard.out.
System.out.println("Unused Declaration Names: ");
for (int i =
0; i < unusedNamesList.size(); i++) {
name = (Name)
unusedNamesList.get(i);
System.out.println("
Line " + name.span().firstLine
+ " " + name.kindImage()
+ " " + name.image());
}
Finally, the compilation unit resources are released, an important step when analyzing lots of units:
compUnit.release();
Conclusion
Give JSIS a try next time you want to prospect for information from your sources. Many of the things you can do with reflection can be done easily with JSIS. If you have one source or thousands, JSIS will scale to automate your static analysis requirements. Visit www.jsistools.com for more information and get a JSIS Personal Evaluation version Free!