Null Analysis

NullPointerException thrown at runtime is one of the most common causes for failure of Java programs. All modern IDEs provide a Null Analysis tool which can detect such programming errors (misuse of potential null Java values) at compile-time.

Principle

The Null Analysis tool is based on Java annotations. Each Java field, method parameter and method return value must be marked to indicate whether it can be null or not.

Once the Java code is annotated, the IDE must be configured to enable Null Analysis detection.

Java Code Annotation

MicroEJ defines its own annotations:

  • @NonNullByDefault: Indicates that all fields, method return values or parameters can never be null in the annotated package or type. This rule can be overridden on each element by using the @Nullable annotation.
  • @Nullable: Indicates that a field, local variable, method return value or parameter can be null.
  • @NonNull: Indicates that a field, local variable, method return value or parameter can never be null.

MicroEJ recommends to annotate the Java code as follows:

  • In each Java package, create a package-info.java file and annotate the Java package with @NonNullByDefault if you use Eclipse or with your custom annotation if you use Android Studio or IntelliJ IDEA (see next section on IDEs configuration). This is a common good practice to deal with non null elements by default to avoid undesired NullPointerException. It enforces the behavior which is already widely outlined in Java coding rules.

    @ej.annotation.NonNullByDefault
    package com.mycompany;
    
  • In each Java type, annotate all fields, methods return values and parameters that can be null with @Nullable. Usually, this information is already available as textual information in the field or method Javadoc comment. The following example of code shows where annotations must be placed:

    @Nullable
    public Object thisFieldCanBeNull;
    
    @Nullable
    public Object thisMethodCanReturnNull() {
      return null;
    }
    
    public void thisMethodParameterCanBeNull(@Nullable Object param) {
    
    }
    

IDE Configuration

Requirements

The project must depend at least on the version 1.3.3 of the ej.api:edc module:

dependencies {
  implementation("ej.api:edc:1.3.3")
}

Project configuration

To enable the Null Analysis tool in Android Studio and IntelliJ IDEA, refer to the official documentation on Configure nullability annotations.

Both IDEs support custom annotations for Nullable and NotNull annotations, but not for NonNullByDefault. Here are the solutions to be able to define all fields, methods return values and parameters of a whole class or package as non null by default:

  • create a custom annotation in your project using the @TypeQualifierDefault annotation, for example NonNullByDefault:

    import javax.annotation.Nonnull;
    import javax.annotation.meta.TypeQualifierDefault;
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    /**
    * This annotation can be applied to a package, class or method to indicate that the class fields,
    * method return types and parameters in that element are not null by default.
    */
    @Documented
    @Nonnull
    @TypeQualifierDefault(
            {
                    ElementType.ANNOTATION_TYPE,
                    ElementType.CONSTRUCTOR,
                    ElementType.FIELD,
                    ElementType.LOCAL_VARIABLE,
                    ElementType.METHOD,
                    ElementType.PACKAGE,
                    ElementType.PARAMETER,
                    ElementType.TYPE
            })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NonNullByDefault {
    }
    

    This requires to add the following dependency in your project:

    compileOnly("com.google.code.findbugs:jsr305:3.0.2")
    
  • add the @NonNull annotation explicitly on each field, method return value or parameter.

MicroEJ Libraries

Many libraries available on Central Repository are annotated with Null Analysis. If you are using a library which is not yet annotated, please contact our support team.

For the benefit of Null Analysis, some APIs have been slightly constrained compared to the Javadoc description. Here are some examples to illustrate the philosophy:

  • System.getProperty(String key, String def) does not accept a null default value, which allows to ensure the returned value is always non null.
  • Collections of the Java Collections Framework that can hold null elements (e.g. HashMap) do not accept null elements. This allows APIs to return null (e.g. HashMap.get(Object)) only when an element is not contained in the collection.

Implementations are left unchanged and still comply with the Javadoc description whether the Null Analysis is enabled or not. So if these additional constraints are not acceptable for your project, please disable Null Analysis.