JavaCasts

Autoboxing - Unboxing

Posted on

Autoboxing - Unboxing

Here’s a funny issue that I ran over a while ago.
We had some code and experienced a NullPointerException, but there could not be a NullPointerException, all involved Objects where tested to not be null. See for yourself, here’s some kind of similar code:

@RequestMapping("/document/{id}")
public void showPublicDocument(@PathVariable Long id) {
    Document document = documents.find(id);
    if (document != null && document.isPublic()) { // <- in this row
        return document;
    } else {
        throw new DocumentNotAccessibleException("document is not public");
    }
}

So this could be a method in a Spring Rest-Controller. The DocumentNotAccessibleException has the annotation to return the status 404. There’s a DocumentService in the variable documents. The bad thing is that there can only be a NullPointerException if documents is null, right? There’s no other call on a object that can be null, but it’s checked before that also the document is not null, so where does this exception come from?

If you know about this topic and have checked with the subject of this JavaCast, you’ll know that this is a topic on autoboxing or unboxing. Autoboxing/unboxing was introduced with java 1.5. It’s about primitive and their object wrapper types.

So here’s an example that you can also find on github.

Document document = documents.find(123l);
if (document != null && document.isPublic()) {
    LOGGER.info("Found document: " + document.getName());
} else {
    LOGGER.info("Could not find document");
}

The method isPublic() on the Document-class does return a Boolean. This is not a boolean (the primitive type). If this code is compiled, the java-compiler “unboxes” the Boolean class to a primitive boolean.
You can use a java-decompiler to see, what actually was created when this code was compiled:

Document document = this.documents.find(Long.valueOf(123L));
if (document != null && document.isPublic().booleanValue()) {
// ...

Now you see what has happened. The method isPublic() returned a null-value. On this value the method booleanValue() is called and this caused the NullPointerException. But you don’t only see the unboxing of the boolean value, the long-value that we used as the id of the document is actually a Long. And this is also converted with Long.valueOf(123L).

So here’s the list of primitive types and their corresponding wrapper-class:

Primitive type Wrapper class
boolean Boolean
byte Byte
char Character
float Float
int Integer
long Long
short Short
double Double

Sharing is caring!