XUtils

NullAway

Eliminates NullPointerExceptions with low build-time overhead.


NullAway: Fast Annotation-Based Null Checking for Java Build Status Coverage Status

NullAway is a tool to help eliminate NullPointerExceptions (NPEs) in your Java code. To use NullAway, first add @Nullable annotations in your code wherever a field, method parameter, or return value may be null. Given these annotations, NullAway performs a series of type-based, local checks to ensure that any pointer that gets dereferenced in your code cannot be null. NullAway is similar to the type-based nullability checking in the Kotlin and Swift languages, and the Checker Framework and Eradicate null checkers for Java.

NullAway is fast. It is built as a plugin to Error Prone and can run on every single build of your code. In our measurements, the build-time overhead of running NullAway is usually less than 10%. NullAway is also practical: it does not prevent all possible NPEs in your code, but it catches most of the NPEs we have observed in production while imposing a reasonable annotation burden, giving a great “bang for your buck.”

Gradle

Annotation Processors / Generated Code

Some annotation processors like Dagger and AutoValue generate code into the same package namespace as your own code. This can cause problems when setting NullAway to the ERROR level as suggested above, since errors in this generated code will block the build. Currently the best solution to this problem is to completely disable Error Prone on generated code, using the -XepExcludedPaths option added in Error Prone 2.1.3 (documented here, use options.errorprone.excludedPaths= in Gradle). To use, figure out which directory contains the generated code, and add that directory to the excluded path regex.

Note for Dagger users: Dagger versions older than 2.12 can have bad interactions with NullAway; see here. Please update to Dagger 2.12 to fix the problem.

Code Example

Let’s see how NullAway works on a simple code example:

static void log(Object x) {
    System.out.println(x.toString());
}
static void foo() {
    log(null);
}

This code is buggy: when foo() is called, the subsequent call to log() will fail with an NPE. You can see this error in the NullAway sample app by running:

cp sample/src/main/java/com/uber/mylib/MyClass.java.buggy sample/src/main/java/com/uber/mylib/MyClass.java
./gradlew build

By default, NullAway assumes every method parameter, return value, and field is non-null, i.e., it can never be assigned a null value. In the above code, the x parameter of log() is assumed to be non-null. So, NullAway reports the following error:

warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
    log(null);
        ^

We can fix this error by allowing null to be passed to log(), with a @Nullable annotation:

static void log(@Nullable Object x) {
    System.out.println(x.toString());
}

With this annotation, NullAway points out the possible null dereference:

warning: [NullAway] dereferenced expression x is @Nullable
    System.out.println(x.toString());
                        ^

We can fix this warning by adding a null check:

static void log(@Nullable Object x) {
    if (x != null) {
        System.out.println(x.toString());
    }
}

With this change, all the NullAway warnings are fixed.

For more details on NullAway’s checks, error messages, and limitations, see our detailed guide.


Articles

  • coming soon...