16

I was wondering if there is a way to dump the state of all local variables when there is an exception, to get a better idea of the state of the environment that caused the exception. Below the variable idsToDump is unknown at run time and I want to find out the state at which value in the collection is causing the NPE.

Example:

public static void main(String[] args) {
    HashMap<Integer, String> employees = new HashMap<Integer, String>();
    employees.put(1, "James");

    Integer[] idsToDump = new Integer[] { 1, 2, 3 };
    for (Integer employeeId : idsToDump) {
        String name = employees.get(employeeId).toLowerCase();
        System.out.println(name + " is employee number: " + employeeId);
    }

}

output:

james is employee number: 1
Exception in thread "main" java.lang.NullPointerException

Question: Is there some JVM argument that I can pass to dump information about the current state of the local variables? ie we get

java.lang.NullPointerException

and (this is the part I'm after)

values: employeeId=2

I want to be able to do this on a client site, so no access to Eclipse or debugging tools, looking for just JVM arguments, can't make code changes either. I have looked through them but couldn't really find anything. In the meantime I'll keep searching there too ;)

user1160931
  • 228
  • 2
  • 5
  • AFAIK there's no way to do that, especially not using VM arguments. – Thomas Jan 20 '12 at 16:13
  • 1
    Why can't you use try/catch and print the variables in the catch? – Jivings Jan 20 '12 at 16:19
  • You can do this with a debugger. You can add a breakpoint when the exception is run and you will be able to see all the local variables. – Peter Lawrey Jan 20 '12 at 16:21
  • Just noticed `no access to Eclipse or debugging tools, looking for just JVM arguments, can't make code changes either` – Jivings Jan 20 '12 at 16:21
  • 2
    If you have access to JVM arguments, you have access to debugging tools. see http://www.ibm.com/developerworks/opensource/library/os-eclipse-javadebug/index.html – artbristol Jan 20 '12 at 16:24
  • May be relevant: https://stackoverflow.com/questions/6816951/can-i-get-information-about-the-local-variables-using-java-reflection – aff May 06 '19 at 03:08

6 Answers6

4

I came across a commercial product that does this by simply using a startup -agentlib JVM agent param. I haven't used it yet but intend on giving it a try as it looks very promising.

https://www.takipi.com/product

Anyone have experience with this product?

Sanjiv Jivan
  • 1,922
  • 18
  • 19
  • Takipi (overops.com) is an amazingly useful product for java state capture and aggregations. Highly recommend it for those who can afford it. – Stephen McKain Aug 12 '19 at 16:40
2

The easiest thing to do is to run this code in a debugger and step through it. If you can't debug the code then you can use a try/catch block and set employeeId outside of this like:

int debugEmployeeId = -1;
try {
    Integer[] idsToDump = new Integer[] { 1, 2, 3 };
    for (Integer employeeId : idsToDump) {
        debugEmployeeId = employeeId;
        ...
} catch (Exception e) {
    throw new Exception("Missing employeeId = " + Integer.toString(debugEmployeeId));
}
Michael Shopsin
  • 2,055
  • 2
  • 24
  • 43
  • 1
    Generic exceptions are bad. OP said it's a `NullPointerException` so catch and rethrow that. – Jivings Jan 20 '12 at 16:21
  • 1
    Also `no access to Eclipse or debugging tools, looking for just JVM arguments, can't make code changes either`. – Jivings Jan 20 '12 at 16:22
  • Agreed generic exceptions are bad form, for a quick piece of debug code or a requirement not to throws exceptions upwards are the only reasons to use the class. At least in Java `catch (Exception)` is an option, in C++ `catch (...)` doesn't always work. – Michael Shopsin Jan 20 '12 at 16:31
  • I don't think his request can be done without code changes or a remote debugger. – Michael Shopsin Jan 20 '12 at 16:33
  • 1
    That's what I thought with all my (6) years of Java development, however I thought I would run this by a higher being of developers ;) – user1160931 Jan 20 '12 at 17:02
  • Flattery with get you everywhere. – Jivings Jan 20 '12 at 17:25
2

Given all your restrictions, I can't recommend anything else apart from jdb. Fire that bad boy up and start stepping through the client code line by line. I know you said no debugging tools, but unless they are a JRE only environment you should have jdb installed already.

Perception
  • 79,279
  • 19
  • 185
  • 195
  • Hey Preception, I think this might be the best approach (provided that the client has JDK installed), we ship them JRE only. I'm going to try this on my dev environment and see how well it works. If this pans out, I'll deploy a JDK there is need be. – user1160931 Jan 20 '12 at 17:04
1

Although you have mentioned that you are not able to do any code changes, here a hint for the case that code changes are still possible: A handy tool to get some more information about the exception is the method "printStackTrace" of the thrown exception object. You may want to use something like this.


try {
...
}
catch ( Exception e ) {
  System.out.println( "Exception occured! Reason: " + e.printStackTrace() );
}

boto
  • 455
  • 2
  • 13
0

Your best option, afaik, is the old manual way: use some sort of logging (be it Log4J, or just stdout), and to explicitly record the variables you're interested in via a catch block.

Brian
  • 6,391
  • 3
  • 33
  • 49
0

Like Thomas, I don't know of any current method that can dump variables. However, I believe you want to do so to aid you in your debugging. Here are some simple methods which I use to debug my code using just the console:

1.Learn to read the stacktrace when the exception occurs. It gives you a lot of information on what could be potentially causing the exception. If the particular line that the stacktrace is pointing to doesn't seem to have anything wrong, track back the code and see if it was a prior object that is causing the exception. For example (using some sample code and methods):

Book book = null;
Bookshelf bookshelf = new Bookshelf();
bookshelf.add(book);
bookshelf.getBooks();

Something like that will cause the NPE stacktrace to point to bookshelf, but actually it is book that is causing the NPE.

2.Print out the variables that you suspect are causing the NPE.

for (Integer employeeId : idsToDump) {
  System.out.println(employeeId);
  String name = employees.get(employeeId).toLowerCase();
  System.out.println(name + " is employee number: " + employeeId);
}

Your output will be:

1
2

And then you'll know that 2 is causing the NPE.

3.Comment out the suspicious code and systematically uncomment out the code until the exception occurs, or vice-versa.

Although you may find it tedious and frustrating at times, it really does help in your foundation because with enough practice, you'll soon be able to intuitively spot where the error usually occurs (and hence spend less time on future debugging).

Wei Hao
  • 2,756
  • 9
  • 27
  • 40
  • 1. I can read the stacktrace for the logs, and I know I'm getting a null from my map. Either the key is not in the map OR the value for the map is null, either case I want to dump the key. 2. Can't print out, since this is a closed jar now. 3. Can't make code changes. – user1160931 Jan 20 '12 at 16:58