Using BCEL to reduce the problem of NullPointerExceptions

Inigo Surguy

The problem with the NullPointerException

Of all Java's exceptions, the NullPointerException is the most annoying.

Rather than being triggered when an object is incorrectly set to null, they instead occur when methods are called on an object that is null; giving a stacktrace that will often point to code that is far removed from the actual program mistake. This makes debugging them hard

I will show several standard ways of reducing the difficulty of debugging NullPointerExceptions, and then a method using the free Bytecode Engineering Library (BCEL) from the Apache Foundation.

Avoiding NullPointerExceptions by writing code that doesn't assign references to null

Unfortunately, this approach isn't always available- often third party code will be returning null values.

Avoiding NullPointerExceptions with guard clauses and assertions

A common idiom is to add "guard clauses" to methods to check for null values. For example:

    public void doSomething(String name) {
        if (name=null) { 
            throw new IllegalArgumentException("Name cannot be null");
        }
        // Method code continues...
    }

This helps catch references to null objects closer to their origin, but this slows the program at runtime, and bulks out the sourcecode. Excess code makes a class harder to understand and refactor, even when its very simple.

The latter problem can be solved using JDK 1.4 assertions; thus:

    public void doSomething(String name) {
        assert (name!=null);
        // Method code continues...
    }

This is not only shorter; it can also be disabled at runtime. However, it does still require that boilerplate code is manually added to methods.

Avoiding NullPointerExceptions with BCEL

The guard clause code above is regular and simple, and thus it is easy to automate its inclusion. This can be done in the sourcecode, by writing an editor macro, but this has still has the problems of bulky code. An alternative approach that removes these problems is to use the Bytecode Engineering Library (BCEL) to modify the bytecode at class-load time.

BCEL

With BCEL, we can automatically add the guard clauses to the beginning and return from every method.

The compiler puts an opcode at every expected exit point from a method (but not at every point where an exception could be thrown). If the method returns with a value, then the type of the opcode depends on the type of return value: for an object ARETURN, for an int IRETURN, for a double DRETURN, and so on. If the method is not declared to return a value, the opcode is simply RETURN.

Primitives cannot be null, so the only return opcode that should be checked is ARETURN. This returns the value at the top of the stack.

To respond to a null value, we could check the value and add code to respond to it here. For the sake of flexibility, we instead call a static method with the value.

To do this, we first get a reference to the method, then use a DUP to duplicate the value on the stack (if it was a double or a long, it would have to be a DUP2). Then call the method, which will consume the duplicated value, leavinq the original value on the stack to be returned.

Here is the code:

Download the code

References

There is a good series of articles by Eric Allen of IBM about good practices for avoiding bugs; of which the Null Flag bug pattern article is particularly relevant.

There is more about BCEL at the Jakarta-Apache site and at its old home at SourceForge.

An excellent book on the Java VM, explaining what the bytecode VM instructions are, is Inside the Java 2 Virtual Machine by XXXX (ISBN something).

Sun provides documentation on JDK 1.4 assertions.

Return to index

Return to the index page.