Title: Leveraging JSR-305 null annotations to prevent NullPointerExceptions
[TOC]
# Introduction
The Sling API forces developers to sometimes check for `null` return values. Most prominently this is the case for [`Adaptable.adaptTo`](https://sling.apache.org/apidocs/sling8/org/apache/sling/api/adapter/Adaptable.html#adaptTo-java.lang.Class-) and [`ResourceResolver.getResource`](https://sling.apache.org/apidocs/sling8/org/apache/sling/api/resource/ResourceResolver.html#getResource-java.lang.String-). This is often forgotten, which may lead to `NullPointerException`s. Sling API 2.9.0 introduced the JSR-305 annotations ([SLING-4377](https://issues.apache.org/jira/browse/SLING-4377)) which allow tools to check automatically for missing null checks in the code.
# Annotations
The annotations used within Sling are based on the [JSR-305](https://jcp.org/en/jsr/detail?id=305) which is dormant since 2012. Nevertheless those annotations are understood by most of the tools and used by other Apache Projects like Apache Oak [OAK-37](https://issues.apache.org/jira/browse/OAK-37).
Due to the fact that Eclipse and FindBugs are interpreting annotations differently ([Findbugs-1355](https://sourceforge.net/p/findbugs/bugs/1355/)). Sling only uses the following two different annotations which are supported by both tools:
1. `javax.annotation.CheckForNull` (only on return values which may be `null`)
1. `javax.annotation.Nonnull` (on return values and arguments which are never supposed to be `null`)
Annotations which support setting the default null semantics of return values and or parameters on a package level cannot be leveraged for that reason.
In case no annotations have been set on method arguments those accept `null` as a value. Return values should always be explicitly annotated, as from both cases checks can be derived.
The annotations have a retention policy of `runtime`, therefore bundles using these automatically have a `Import-Package` header listing `javax.annotation`. That package is by default exported by the system bundle (as this package is also part of the [JRE](https://docs.oracle.com/javase/7/docs/api/javax/annotation/package-summary.html)). To be able to resolve the bundle through this exported package from the system bundle you should use the `com.google.code.findbugs:jsr305` artifact in version 3.0.0 as that exports the package `javax.annotation` in no specific version. Newer versions use version directives which automatically restrict the version range for the generated `Import-Package` header to `[3,4)` [which usually cannot be resolved at run time](https://github.com/amaembo/jsr-305/issues/31).
# Use With Eclipse
Eclipse since Juno supports [null analysis based on any annotations](http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Freference%2Fpreferences%2Fjava%2Fcompiler%2Fref-preferences-errors-warnings.htm&anchor=null_analysis). 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/JSR 305 those are
* `javax.annotation.CheckForNull` as **'Nullable' annotation** (primary annotation)
* `javax.annotation.Nonnull` as **'NonNull' annotation** (primary annotation)
![Eclipse Settings for Null analysis](eclipse-settings-null-analysis.png)
Unfortunately Eclipse cannot infer information about fields which are for sure either null or not null (reasoning is available in [https://wiki.eclipse.org/JDT_Core/Null_Analysis/Options#Risks_of_flow_analysis_for_fields](https://wiki.eclipse.org/JDT_Core/Null_Analysis/Options#Risks_of_flow_analysis_for_fields) and [Eclipse Bug 247564](https://bugs.eclipse.org/bugs/show_bug.cgi?id=247564)). This also affecs constants (static final fields) or enums which are known to be non null, but still Eclipse will emit a warning like *The expression of type 'String' needs unchecked conversion to conform to '@Nonnull String'*. The only known workaround is to disable the **"Unchecked conversion from non-annotated type to @NonNull type"** or to annotate also the field with `@Nonnull`.
More information are available at [https://wiki.eclipse.org/JDT_Core/Null_Analysis](https://wiki.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 [lastnpe.org](http://www.lastnpe.org/) and [TraceCompass](https://github.com/tracecompass/tracecompass/tree/master/common/org.eclipse.tracecompass.common.core/annotations). There is no official repository yet though ([Eclipse Bug 449653](https://bugs.eclipse.org/bugs/show_bug.cgi?id=449653)).
[Lastnpe.org](http://www.lastnpe.org/) provides also an m2e extension to ease setting up the classpaths with external annotations from within your pom.xml.
# Use With Maven
## Leveraging Eclipse JDT Compiler (recommended)
You can use Eclipse JDT also in Maven (with null analysis enabled) for the regular compilation. That way it will give out the same warnings/errors as Eclipse and will also consider external annotations.
JDT in its most recent version is provided by the `tycho-compiler-plugin` which can be hooked up with the `maven-compiler-plugin`.
The full list of options for JDT is described in [here](http://help.eclipse.org/neon/index.jsp?topic=%2Forg.eclipse.jdt.doc.user%2Ftasks%2Ftask-using_batch_compiler.htm).
This method was presented by Michael Vorburger in his presentation [The end of the world as we know it](https://www.slideshare.net/mikervorburger/the-end-of-the-world-as-we-know-it-aka-your-last-nullpointerexception-1b-bugs/14).
::xml
maven-compiler-plugin3.5.11.81.8truejdtCLASSPATH-err:nullAnnot,null,-missingNullDefaultorg.eclipse.tychotycho-compiler-jdt1.0.0
## Leveraging FindBugs
You can also let Maven automatically run FindBugs to execute those checks via the **findbugs-maven-plugin**. For that just add the following plugin to your `pom.xml`
::xml
org.codehaus.mojofindbugs-maven-plugin3.0.0InconsistentAnnotations,NoteUnconditionalParamDerefs,FindNullDeref,FindNullDerefsInvolvingNonShortCircuitEvaluationrun-findbugs-fornullcheckscheck
The results are often very imprecise ([MFINDBUGS-208](http://jira.codehaus.org/browse/MFINDBUGS-208)), especially when it comes to line numbers, therefore it is best to start the Findbugs GUI in case of errors found by this plugin via `mvn findbugs:gui`.
# Use With FindBugs
FindBugs evaluates the JSR-305 annotations by default. You can restrict the rules to only the ones which check for those annotations, which are
* InconsistentAnnotations
* NoteUnconditionalParamDerefs
* FindNullDeref
* FindNullDerefsInvolvingNonShortCircuitEvaluation
A complete list of visitors class names in Findbugs can be found in the [sourcecode](https://code.google.com/p/findbugs/source/browse/#git%2Ffindbugs%2Fsrc%2Fjava%2Fedu%2Fumd%2Fcs%2Ffindbugs%2Fdetect%253Fstate%253Dclosed). The according [bug patterns](http://findbugs.sourceforge.net/bugDescriptions.html) have an identifier (in parenthesis) for which you can search in the according Java classes, in case you want to extend the checks.
Findbugs is also integrated in [SonarQube](http://docs.sonarqube.org/display/SONAR/Findbugs+Plugin) but for SonarQube you should now rather use the native Java plugin
(look at [Use with SonarQube](#use-with-sonarqube)).
# Use with SonarQube
At least rule [squid:S2259](https://sonarqube.com/coding_rules#rule_key=squid%3AS2259) in SonarQube supports JSR-305 annotations as well for null checks.