Stop on specific NullPointerException in Eclipse

20. December, 2017

TL;DR: Find the line where the exception occurs and then add a conditional breakpoint which checks the local variables for values that would trigger the exception.

In Eclipse, you can stop on any exception by using the menu Run -> “Add Java Exception Breakpoint…“.

That’s great but it doesn’t help when you want to stop on a certain exception on a certain line. It’s a big problem with code that uses exceptions for control flow – you could have thousands of those exceptions before you get to the one which you care about.

In my case, I had a NullPointerException in java.util.concurrent.ConcurrentHashMap:

    public V get(Object key) {
        Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
        int h = spread(key.hashCode()); <-------- key is null
        ...

I tried to add a conditional breakpoint here with the condition key == null but Eclipse complained that it couldn’t compile the expression (probably missing debug information).

The method was called from Jetty’s ClassInheritanceHandler, so I added a conditional breakpoint there.

That’s another reason to copy method results into local variables before using them.


YouDebug, the Non-interactive Debugger

7. May, 2014

“Non-interactive” and “debugger” seem to be contradictory but bear with me. YouDebug is a tool which allows you to debug a running Java application with a script.

How could this be useful? From the website:

[…]your program fails at a customer’s site with an exception, but you can’t (or don’t want to) reproduce the problem on your computer[…]

Sounds like a familiar problem: Customer has a problem but they can’t give you access for security, legal or technical reasons. You can’t go there (too far away) of even if you could, security won’t let you touch anything.

In a nutshell, YouDebug is a debugger that is controlled by a Groovy script:

breakpoint("com.acme.SubStringTest",7) {
  println "s="+s;
}

This sets a breakpoint in line 7 of “SubStringTest” and then prints the value of the local variable “s”.

Granted, it’s more time-consuming then doing it yourself (and you may need several attempts to get at the bottom of things) but you don’t have to install an IDE at your customer site, you don’t have to bring the source code along and technically, the customer is already running code that you wrote so from a legal and security point of view, this isn’t much different.


Debugging proxy.pac Files

29. August, 2013

I just wrote a small utility to debug proxy.pac files using the excellent pacparser library.

You can find it here (gist).


Debugging v2.0 With Chronon

1. December, 2011

“… Okay, let’s just set a breakpoint there … run again … continue continue continue next next next *argh* run again … continue continue continue next next¬†… Why is it still null?? Who changes this field? Oh, damn … breakpoint … run again … where is that coming from? … oh no …”

Sound familiar? How often do you rerun your code just because you can’t step backwards in time? How often did you ask yourself “who is calling this method?” Or “where did this value come from?”

Meet Chronon. In a nutshell, Chronon runs your code, saves all state changes (method calls, variable assignments) somewhere and allows you to browse the result.

So with this tool, the text above would have been: “… Okay, it’s null here. Where does that value come from? *click* Oh, ok. Who called this method? *click* Oh, I see.”

This makes you find the source of an error much more quickly. Other questions that Chronon can answer:

  • Find all instances of a class that were created. A special window lists all exceptions that were thrown.
  • Step backwards (just like stepping forward)
  • Go to the code that printed a certain output on the Console (just click on the output in the Console window!)
  • Show me all the values of some variable (Post Execution Logging)

The tool is surprisingly fast. You’d expect something like that to hog your computer but collecting the data is pretty quick (just a small increase in the time it takes to execute the code; I didn’t time it).

It does take a mental leap, though. Stop thinking like you were executing the code. It’s more a specialized database browser where the data is all the states of your application.

Things that I don’t like:

  1. Opening a recording takes a few moments (<< 1 minute) while it “decompresses” the recording. I’m not sure what happens here. It seems stupid to compress the latest recording because chances are that you probably want to use it soon. But I guess this stage creates a couple of indexes so the UI can quickly navigate the data, so it’s just an unhappy label.
  2. The plug-in messes with my eclipse.ini! Bad plug-in, down! I understand that Chronon needs lots of RAM. And I think it does take your total memory into account (it allocated 2.5GB of my 8GB). Still, it should ask before doing something like that. And it absolutely should not do it again, after I reset the values to something sane. GCing 2.5GB of RAM does take a long time!

Java tip: Getting most out of exceptions

28. December, 2010

Exceptions should have two purposes: 1. Clean up after an error and 2. help you solve the issue. Sadly, many Java developers often forget about #2.

So you end up with an exception thrown in SignatureFileVerifier (no source). Or even in a native method. The error message is:

Invalid signature file digest for Manifest main attributes

Right. Which tells us exactly … nothing. The stack trace isn’t better:

java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
	at sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:221)
	at sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:176)
	at java.util.jar.JarVerifier.processEntry(JarVerifier.java:233)
	at java.util.jar.JarVerifier.update(JarVerifier.java:188)
	at java.util.jar.JarFile.initializeVerifier(JarFile.java:325)
	at java.util.jar.JarFile.getInputStream(JarFile.java:390)
	at sun.misc.URLClassPath$JarLoader$1.getInputStream(URLClassPath.java:620)
	at sun.misc.Resource.cachedInputStream(Resource.java:59)
	at sun.misc.Resource.getByteBuffer(Resource.java:84)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:249)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
	at org.eclipse.jface.action.LegacyActionTools.initLocalizedModifiers(LegacyActionTools.java:699)
	at org.eclipse.jface.action.LegacyActionTools.findLocalizedModifier(LegacyActionTools.java:356)
	at org.eclipse.jface.action.LegacyActionTools.convertLocalizedAccelerator(LegacyActionTools.java:167)
	at org.eclipse.jface.action.Action.setText(Action.java:665)
	at de.pdark.epen.editor.actions.ForwardAction.(ForwardAction.java:29)
	at de.pdark.epen.editor.actions.ForwardActionTest.testCreate(ForwardActionTest.java:21)

So LegacyActionTools needs a class. Which one? Since I don’t have the source, how can I set a breakpoint?

Simple: Set the breakpoint in the constructor of the exception! Even native code has to pass through here, eventually.


Debugging BIRT: How do I enable logging for OSGi/Equinox?

12. July, 2010

If you ever tried to enable logging for OSGi (Equinox) because starting the BIRT engine fails for mysterious reasons, you will have noticed that BIRT removes all osgi.* options from the System.properties before it launches (see ).

Instead, it expects these options in config.ini (which must be in the current folder):

# Specify the file with the debug options. See the .options file in the org.eclipse.osgi*.jar for examples
osgi.debug=/path/to/file/with/debug.options
# Change the classloader. Possible values are: "app", "fwk", "boot" (default)
# app: Use the current SystemClassLoader
# boot: Use the boot classloader
# fwk: Use the classloader which was used to load OSGi.
#osgi.parentClassloader=fwk

Use fwk if you see errors because of missing XML parser classes. The Java runtime has a private static field which contains the XML parser factory and if you touch any XML code before you start OSGi, then that field will be set and OSGi will be forced to use this XML parser — only the default boot classloader can’t see the parser. Bummer.