A Tool for Analyzing Exception Flow in Java Programs
OverviewJex is a static analysis tool that provides information about the exceptions that can be raised in a Java program. For each method of each class, Jex outputs a description of all exceptions that can be raised in the method. The description shows the origin of each exception. Here is an example describing the flow of exceptions for an hypothetical constructor, in the Jex format.
<init>(java.lang.String,boolean) throws IOException
catch( java.lang.IOException )
In this example, we see that an SecurityException can be raised as a result of the call to method checkWrite of class SecurityManager. Furthermore, in the try block, IOExceptions can result from the calls to methods openAppend and open of class FileOutputStream, and a NullPointerException can be raised by the run-time environment. The catch clause declares to catch IOException and in the corresponding block, a FileNotFoundException is explicitly raised using the keyword throw. General information about the information contained in Jex files can be found below. The view of exception flow produced by Jex is more precise and more complete than the information available through exception interfaces (i.e, the "throws" list in method declarations).Precise information Jex includes more precise information because it includes the types of the exceptions raised by subsumption and by polymorphic calls. For example, if a method declares to raise IOExceptions, but in reality raises both IOExceptions and FileNotFoundExceptions (a subtype of IOException), the exception interface must only declare the supertype (IOException). Jex will report the different subtypes of IOExceptions that can be raised. Jex also reports the origin of exceptions stemming from polymorphic calls by using a conservative class hierarchy analysis algorithm. Complete information The information reported by Jex is also more complete because it includes information about the types of unchecked exceptions that can be raised. General information on Jex Jex was developed in 1998 in the Department of Computer Science at the University of British Columbia by Martin Robillard with contributions from Gail Murphy. It was introduced in this ESEC/FSE'99 paper. This TOSEM paper has the most complete description of Jex.
Download and InstallationThis version of Jex was developed as an extension to KJC, an open source Java compiler. It also uses the gnu.getopt package and antlr.
Jex is freely available under the terms of the GNU Public License.
Jex and its dependencies are written in Java. To install:
User GuideThe basic unit of information needed by the Jex tool is a Jex file: a text file containing exception flow information. In order to produce a Jex file for a target class, the Jex files for all the classes used by this target class must exist. The approach Jex uses to deal with bootstrapping, cyclic dependencies, and classes with unavailable source code, is to generate a bunch of stubs (minimal jex files) for all classes considered for the analysis and iterate until fix points are reached. The analysis always converges. To manage all the jex files, Jex uses a "Jex Path", a root directory where jex files are stored in a hierarchical directory structure similar to the one of the CLASSPATH.
The first thing to do is to generate the stubs for all (or part of) the java class libraries. These stubs are Jex files that typically won't be augmented by more analysis, and thus can be generated once and left alone. It is NOT necessary to have the source code for generating stubs for a class.
To generate stubs for the java libraries:
You can now try the quickstart example, or read on for general information.
Setting up an analysis
To analyze source code with Jex, it is necessary to write a Jex configuration file. Here's a template. The file must follow the following rules:
Where <token> is either: <jexpath>, <package>, <file>, or <dir>
The <jexpath> value should be the root directory for jex files. It is only possible to specify one Jex path. If many <jexpath> tokens are found in the Jex config file, the value of the last one will be used.
The <package> value should be a valid, fully-qualified package name (e.g., java.lang), to include for class-hierarchy analysis. Class hierarchy analysis is used to conservatively determine what method bodies can be executed for each method call. As many package descriptors as desired can be used. For instance, if java.lang and java.io are specified, calls to Object.toString() will be considered to raise all the exceptions raised by the calls to toString() of all the classes in java.io and java.lang. If a method call is detected in the source code for a class that is not part of the classes included with the packages descriptors, a warning will be issued.
The <genstub> value should be a valid, fully-qualified package name (e.g., com.mypackage), to generate stubs for at the beginning of an analysis. Stubs for library code that is not analyzed should be only generated once and left alone. A genstub command for them is not necessary. However, the <genstub> can be added to a config file when it is desired to re-generate jex files from scratch. This is necessary when source code is modified and jex files become out of sync. A command-line option gives the user the possibility of regenerating the jex files or not, so adding <genstub> is not a strong commitment.
the <dir> value should be a valid directory where Java source files can be found. The <dir> value indicates to jex to analyze all the java source files in the specified directory.
The <file> value should be a valid java source file. The <file> value indicates to jex to analyze the single source file.
Any combinations of <file> and <dir> tokens can be used.
When writing a jexconfig file, it is important to keep in mind that Jex processes all the source files specified until a fix point is reached. This can be slow. To speed up the analysis of a entire application, it is faster to analyze separate, self-contained groups of source files separately. For instance, if I have packages A (50 files), B (100 files), and C (200 files), I could include these 3 packages using the dir command and launch an analysis. This would result in analyzing 350 files until a fix point is reached. If package C is known not to depend on neither A nor B, it will be faster to analyze C in isolation, and then analyze A and B together.
Running an analysis
Jex makes heavy use of introspection. To successfully run an analysis, the Java code to be analyzed must be compiled and the corresponding class files must be properly installed and visible through the CLASSPATH. The java class libraries (typically, rt.jar) must also be explicitly in the classpath.
To run an analysis, write a jexconfig file describing the desired analysis, and enter:
java ca.ubc.cs.jex.Jex jexconfig.txt
Available command-line options are:
Once the analysis is complete, Jex will generate a file jex-report.txt in the directory from which the application was launched. This report contains the following information:
This is an exception that can be raised by some operations of the JVM. These correspond to section 15.6 of the Java language specification.
<exception type> <class><method signature>, e.g., java.io.IOException:java.lang.io.File.getCanonicalPath()
This is an exception that can be raised by a method call.
throws <exception type>, e.g., throws IOException
This is an exception that can be raised explicitly using the throws keyword.
ExampleYou can make sure your installation works using the following example, taken from the Java Tutorial. This example assumes that you have successfully generated the stubs for the Java libraries.
ContactJex is an unsupported legacy project. For general questions, please contact Martin Robillard.
Last updated 22 June 2007