Trace your steps in Java 1.4
Tutorial Details:
Java Tip 124: Trace your steps in Java 1.4
Java Tip 124: Trace your steps in Java 1.4
By: By John D. Mitchell
Locate runtime code with getStackTrace()
don't know about you, but I really like to know where I am. Being a guy, I'm never lost, but sometimes I just don't know where I am. Some places, such as malls, have maps with "You Are Here" indicators. Similarly, Java now lets us figure out our location with the system's help. In this tip, I'll show you how to extract this location information from the system in a consistent and reliable manner.
I firmly believe the runtime system should provide enough metadata about the system itself so programs can make better decisions and complete tasks. Java has been able to introspect and reflect on classes for some time, but until now it has lacked the simple ability to map runtime code back to its position in the source code file. The pre-Java 1.4 solution was to manually parse an exception's stack trace. Now, with Java 1.4, we have a better solution.
Pull apart a stack trace?
The pre-Java 1.4 workaround to gathering location information was to manually parse an exception's printStackTrace() output. Here's an example of a simple stack trace:
java.lang.Throwable
at boo.hoo.StackTrace.bar(StackTrace.java:223)
at boo.hoo.StackTrace.foo(StackTrace.java:218)
at boo.hoo.StackTrace.main(StackTrace.java:54)
Pulling the above code apart is not a major parsing problem. But how about this?
java.lang.Throwable
at
boo.hoo.StackTrace$FirstNested$SecondNested.(StackTrace.java:267)
at boo.hoo.StackTrace$FirstNested.(StackTrace.java:256)
at boo.hoo.StackTrace.(StackTrace.java:246)
at boo.hoo.StackTrace.main(StackTrace.java:70)
Ugh. What does all that weird goobley-guk really mean, and why on earth should I have to parse it? Obviously, the system already tracks that location information, since it's able to build those stack traces. So why isn't that location information available directly? Well, with Java 1.4, it finally is.
In addition, keep in mind that in the face of JIT (just-in-time) compilers and dynamic, optimizing compilers like Sun Microsystems' HotSpot, file and line number information may not exist. The goal of "performance or bust" can certainly be bothersome.
Java 1.4 Throwable to the rescue!
After tolerating years of complaints, Sun Microsystems has finally extended the java.lang.Throwable class with the getStackTrace() method. getStackTrace() returns an array of StackTraceElement s, where each StackTraceElement object provides the means to more or less directly extract location information.
To acquire that mapping information, you still create a Throwable instance at the point of interest in your code:
//...
public static void main (String[] args)
{
Throwable ex = new Throwable();
//...
This code positions that point at the start of main() .
Of course, it's useless to just gather that information without doing something with it. For this tip, we will use each underlying method of the StackTraceElement s to extract and display all the information we can.
The example program, StackTrace.java , shows how to extract the location information with several examples. You will need the J2SE (Java 2 Platform, Standard Edition) 1.4 SDK to compile and run the example program.
To extract and display the mapping information, the example code uses a helper method, displayStackTraceInformation() , with the following basic usage idiom:
//...
public void crashAndBurnout()
{
//...
displayStackTraceInformation (new Throwable());
//...
}
//...
The displayStackTraceInformation() code is pretty straightforward:
public static boolean displayStackTraceInformation (Throwable ex,
boolean displayAll)
{
if (null == ex)
{
System.out.println ("Null stack trace reference! Bailing...");
return false;
}
System.out.println ("The stack according to printStackTrace():\n");
ex.printStackTrace();
System.out.println ("");
StackTraceElement[] stackElements = ex.getStackTrace();
if (displayAll)
{
System.out.println ("The " + stackElements.length +
" element" +
((stackElements.length == 1) ? "": "s") +
" of the stack trace:\n");
}
else
{
System.out.println ("The top element of a " +
stackElements.length +
" element stack trace:\n");
}
for (int lcv = 0; lcv < stackElements.length; lcv++)
{
System.out.println ("Filename: " +
stackElements[lcv].getFileName());
System.out.println ("Line number: " +
stackElements[lcv].getLineNumber());
String className = stackElements[lcv].getClassName();
String packageName = extractPackageName (className);
String simpleClassName = extractSimpleClassName (className);
System.out.println ("Package name: " +
("".equals (packageName)?
"[default package]" : packageName));
System.out.println ("Full class name: " + className);
System.out.println ("Simple class name: " + simpleClassName);
System.out.println ("Unmunged class name: " +
unmungeSimpleClassName (simpleClassName));
System.out.println ("Direct class name: " +
extractDirectClassName (simpleClassName));
System.out.println ("Method name: " +
stackElements[lcv].getMethodName());
System.out.println ("Native method?: " +
stackElements[lcv].isNativeMethod());
System.out.println ("toString(): " +
stackElements[lcv].toString());
System.out.println ("");
if (!displayAll)
return true;
}
System.out.println ("");
return true;
} // End of displayStackTraceInformation().
Basically, we call getStackTrace() on the passed-in Throwable , and then loop through the individual StackTraceElement s, extracting as much mapping information as possible.
Note the bit of cruft the displayAll parameter introduces. displayAll lets the calling site decide whether or not to display all the StackTraceElement s or just the stack's topmost element. The example program uses the displayAll parameter to restrict the output to a reasonable amount.
Most of the stack trace information is directly useful. For example, the StackTraceElement.getMethodName() returns a string that contains the method name, while StackTraceElement.getFileName() returns a string with the original source filename. Read the StackTraceElement Javadoc for the complete list of methods.
Class names galore!
As you probably noticed, the displayStackTraceInformation() code uses several additional helper methods to pull apart the value returned by StackTraceElement.getClassName() . Those helper methods are needed because StackTraceElement.getClassName() returns the class's fully qualified name, and StackTraceElement has no other methods to provide the underlying parts of the fully qualified class name. We'll learn about each additional helper method by working through the various example uses of displayStackTraceInformation() .
Default vs. named packages
Given the fully qualified class name, extractPackageName() gives the name of the package in which the class resides:
public static String extractPackageName (String fullClassName)
{
if ((null == fullClassName) || ("".equals (fullClassName)))
return "";
int lastDot = fullClassName.lastIndexOf ('.');
if (0 >= lastDot)
return "";
return fullClassName.substring (0, lastDot);
}
Basically, extractPackageName extracts everything preceding the last dot in the fully qualified class name. That preceding information just happens to be the package's name.
Note: You can comment/uncomment the package statement at the top of StackTrace.java to explore the difference between running the example program in the default, unnamed package versus running it in the boo.hoo package. For example, when uncommented, the display of the topmost stack element for the call to bar() from foo() from main() should look like this:
Filename: StackTrace.java
Line number: 227
Package name: boo.hoo
Full class name: boo.hoo.StackTrace
Simple class name: StackTrace
Unmunged class name: StackTrace
Direct class name: StackTrace
Method name: bar
Native method?: false
toString(): boo.hoo.StackTrace.bar(StackTrace.java:227)
Alternatively, if you comment out the package statement, then the above stack element should resemble this:
Filename: StackTrace.java
Line number: 227
Package name: [default package]
Full class name: StackTrace
Simple class name: StackTrace
Unmunged class name: StackTrace
Direct class name: StackTrace
Method name: bar
Native method?: false
toString(): StackTrace.bar(StackTrace.java:227)
Can class names ever be simple?
The next helper method we use is extractSimpleClassName() . As you'll see, that method's results are not necessarily simple, but I want to clearly distinguish this simplified class name from the fully qualified class name.
Basically, extractSimpleClassName() complements extractPackageName() :
public static String extractSimpleClassName (String fullClassName)
{
if ((null == fullClassName) || ("".equals (fullClassName)))
return "";
int lastDot = fullClassName.lastIndexOf ('.');
if (0 > lastDot)
return fullClassName;
return fullClassName.substring (++lastDot);
}
In other words, extractSimpleClassName() returns everything after the last dot ( . ) from the fully qualified class name. For example, from the same call to bar() above, we see that the simple class name is just StackTrace , whether or not the code is part of the default package or a named package.
We get more interesting results when we turn our attention to nested classes. In the example program, I created two levels of nested, named classes ( FirstNested and FirstNested.SecondNested ) along with an additional, anonymous inner class (inside FirstNested.SecondNested ).
The whole nested usage starts with:
public StackTrace (boolean na)
{
StackTrace.FirstNested nested = new StackTrace.FirstNested();
}
Note that the boolean parameter ( na ) means nothing. I just added it since other constructors need to be distinguished.
Here are the nested classes:
public class FirstNested
{
public FirstNested()
{
StackTrace.displayStackTraceInformation (n
Read
Tutorial at: Click here to view the tutorial
Rate Tutorial: Trace your steps in Java 1.4
View Tutorial: Trace your steps in Java 1.4
Related
Tutorials:
The magic of Merlin - JavaWorld March 2001
The magic of Merlin - JavaWorld March 2001 |
J2SE 1.4
premieres Java's assertion
capabilities, Part
1
J2SE 1.4
premieres Java's assertion
capabilities, Part
1 |
Diagnose common runtime problems with
hprof
Diagnose common runtime problems with
hprof |
Cut down on
logging errors with Jylog
Cut down on
logging errors with Jylog |
Java security evolution
and concepts, Part 5
Java security evolution
and concepts, Part 5 |
Trace your steps in Java 1.4
Trace your steps in Java 1.4 |
Bridge the gap between Java and Twain
Bridge the gap between Java and Twain |
Put Java in the fast lane
Put Java in the fast lane |
All that JAAS
All that JAAS |
Overcome J2SE
1.3-1.4 incompatibilities
Overcome J2SE
1.3-1.4 incompatibilities |
Beware the dangers of
generic Exceptions
Beware the dangers of
generic Exceptions |
Sizeof for
Java
Sizeof for
Java |
Tracing in a multithreaded, multiplatform environment
Tracing in a multithreaded, multiplatform environment
In \"Use a consistent trace system for easier debugging,\" Scott Clee showed you how to trace and log from a custom class to provide a consistent tracing approach across your applications. This approa |
JXMLAppKit 2.0
JXMLAppKit is a pure Swing java framework for editing an XML document with multiple XML editors. |
JView 2004 - J2EE Performance Management Software - Version 1.4
JView 2004 Enterprise Edition available now!
JView 2004 is the leading J2EE Production Performance Monitor and Java Performance Tuning solution, providing precise real-time performance metrics to assist you in ensuring your performance requirements a |
Turn EJB components into Web services
Summary
Web services have become the de facto standard for communication among applications. J2EE 1.4 allows stateless Enterprise JavaBeans (EJB) components to be exposed as Web services via a JAX-RPC (Java API for XML Remote Procedure Call) endpoint, al |
JDock 1.1 - Swing docking framework
JDock is a pure java swing framework for managing, moving and resizing inner windows or components using a layout manager like a BorderLayout or a GridBagLayout.
|
HtmlCalendar bean ver. 1.4
Java bean allows you to generate Calendar for your HTML pages. |
Network Programming with JavaTM 2 Platform, Standard Edition 1.4 (J2SETM)
This article provides an overview of the new features and enhancements in the Java 2 Platform, Standard Edition 1.4 (J2SE), and shows you how to use them effectively. |
J2SE Platform Migration Guide (pdf)
This guide helps developers migrate Java applets, standalone applications, Java Web Start applications and development tools from version 1.3 and 1.4 of the Java platform to version 5.0. |
|
|
|