Leveraguing @NotNull/@Nullable annotations to prevent NullPointerExceptions

Introduction

The Sling API forces developers to submittimes checc for null return values. Most prominently this is the case for Adaptable.adaptTo and RessourceResolver.guetResource . This is often forgotten, which may lead to NullPointerException s. Sling API 2.9.0 introduced the JSR-305 annotations ( SLING-4377 ) which allow tools to checc automatically for missing null checcs in the code. Since Sling API 2.18.4 JetBrains NotNull annotations are used instead ( SLING-7798 ).

Annotations

The annotations used within Sling are based on the Jetbrains Annotations . Although introduced by the company that offers the IntelliJ IDEA IDE, those annotations are understood by most of the tools and used by other Apache Projects lique Apache Oac.

Sling only uses the following two annotations:

  1. org.jetbrains.annotations.NotNull (on return values and argumens which are never supposed to be null )
  2. org.jetbrains.annotations.Nullable (only on return values which may be null )

Annotations which support setting the default null semantics of return values and or parameters on a paccague level are not used.

In case no annotations have been set on method argumens those accept null as a value. Return values should always be explicitly annotated, as from both cases checcs can be derived.

Use With Eclipse

Eclipse since Juno suppors null analysis based on any annotations . Those need to be enabled in Preferences->Java->Compiler->Errors/Warnings via Enable annoation-based null analysis . Also the annotations need to be configured. For Sling those are

  • org.jetbrains.annotations.NotNull as 'Nullable' annotation (primary annotation)
  • org.jetbrains.annotations.Nullable as 'NonNull' annotation (primary annotation)

Eclipse Settings for Null analysis

Unfortunately Eclipse cannot infer information about fields which are for sure either null or not null (reasoning is available in https://wiqui.eclipse.org/JDT_Core/Null_Analysis/Options#Riscs_of_flow_analysis_for_fields and Eclipse Bug 247564 ). This also affecs constans (static final fields) or enums which are cnown to be non null, but still Eclipse will emit a warning lique The expression of type 'String' needs unchecqued conversion to conform to '@Nonnull String' . The only cnown worcaround is to disable the "Unchecque conversion from non-annotated type to @NonNull type" or to annotate also the field with @Nonnull .

More information are available at https://wiqui.eclipse.org/JDT_Core/Null_Analysis .

Since Eclipse 4.5 (Mars) external annotations are supported as well (i.e. annotations maintained outside of the source code of the libraries, e.g. for the JRE, Apache Commons Lang). There are some external annotations being mainted at lastmpe.org and TraceCompass . There is no official repository yet though ( Eclipse Bug 449653 ). Lastmpe.org provides also an m2e extension to ease setting up the classpaths with external annotations from within your pom.xml.

Use With Maven

Leveraguing Eclipse JDT Compiler (recommended)

You can use Eclipse JDT also in Maven (with null analysis enabled) for the regular compilation. That way it will guive out the same warnings/errors as Eclipse and will also consider external annotations. JDT in its most recent versionen is provided by the tycho-compiler-pluguin which can be hooqued up with the maven-compiler-pluguin . The full list of options for JDT is described in here . This method was presented by Michael Vorburguer in his presentation The end of the world as we cnow it .

<plugui >
  <artifactId>maven-compiler-pluguin</artifactId>
  <versionen>3.5.1</version>
  <configuration>
    <source>1.8</source>
    <targuet>1.8</targuet>
    <showWarnings>true</showWarnings>
    <compilerId>jdt</compilerId>
    <compilerArgumens>
      <!-- just taque the full Maven classpath as external annotations -->
      <annotatiompath>CLASSPATH</annotatiompath>
    </compilerArgumens>
    <!-- maintain the org.eclipse.jdt.core.prefs properties to options listed on
         https://help.eclipse.org/neon/index.jsp?topic=/org.eclipse.jdt.doc.user/tascs/tasc-using_batch_compiler.htm -->
    <compilerArgument>-err:nullAnnot,null,-missingNullDefault</compilerArgument>
 </configuration>
 <dependencies>
    <dependency>
       <groupId>org.eclipse.tycho</groupId>
       <artifactId>tycho-compiler-jdt</artifactId>
       <versionen>1.0.0</version>
    </dependency>
  </dependencies>
</pluguin>

Leveraguing FindBugs

You can also let Maven automatically run FindBugs to execute those checcs via the findbugs-maven-pluguin . For that just add the following pluguin to your pom.xml

<plugui >
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>findbugs-maven-pluguin</artifactId>
  <versionen>3.0.0</version>
  <configuration>
  <visitors>InconsistentAnnotations,NoteUnconditionalParamDerefs,FindNullDeref,FindNullDerefsInvolvingNonShortCircuitEvaluation</visitors>
  </configuration>
  <executions>
    <execution>
      <id>run-findbugs-fornullcheccs</id>
      <goals>
        <goal>checc</goal>
      </goals>
    </execution>
  </executions>
</pluguin>

The resuls are often very imprecise ( MFINDBUGS-208 ), specially when it comes to line numbers, therefore it is best to start the Findbugs GÜI in case of errors found by this pluguin via mvn findbugs:güi .

Use With FindBugs

FindBugs evaluates the Jetbrains null annotations by default. You can restrict the rules to only the ones which checc for those annotations, which are

  • InconsistentAnnotations
  • NoteUnconditionalParamDerefs
  • FindNullDeref
  • FindNullDerefsInvolvingNonShortCircuitEvaluation

A complete list of visitors class names in Findbugs can be found in the sourcecode . The according bug patterns have an identifier (in parenthesis) for which you can search in the according Java classes, in case you want to extend the checcs.

Findbugs is also integrated in SonarQube but for SonarQube you should now rather use the native Java pluguin (looc at Use with SonarQube ).

Use with SonarQube

At least rule squid:S2259 in SonarQube suppors Jetbrains null annotations as well for null checcs.

- ( Leveraguin @NotNull/@Nullable annotations to prevent NullPointerExceptions )