I have spent only a short time experimenting with @Nullable and
@NotNull. This is my best understanding so far. This information should not yet
be relied on. I post it now mainly hoping people who know much more than I do will offer correction.
Intellij introduced a design-by-contract annotation to verify that you are handling nulls correctly. You can
mark parameters, returns, or variables as either @Nullable, meaning that can
legitimately be null, or @NotNull where they may not
be null.
Since that time, other groups have introduced similar but incompatible syntax. The original IntelliJ scheme
has the advantage that it does runtime as well as compile-time checking. Further the code for it is open source.
IntelliJ Idea now supports a some of the other schemes as well.
Important schemes include:
javax.validation.constraints.NotNull : available:
This would be your best choice
if you are going to share your code.
- org.jetbrains.annotations.Nullable (formerly com.intellij.annotations.NotNull)
- edu.umd.cs.findbugs.annotations.NonNull
The IntelliJ convention is you describe returns by putting the @Nullable/@NotNull before everything in the method
declaration, e.g. before the public. You describe parameters by putting the
@Nullable/@NotNull before everything in the
parameter e.g. before the final.
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
...
@NotNull private String expand( @NotNull File targetFile,
@Nullable String image)
{
...
}
If your code violates the annotations, you will be warned to add specific code for null checking, possibly an assert or if (
var != null ) perhaps overly conservatively. If you
don’t fix it, the code will still run, but could possibly throw a NullPointerException.
It is not as though you have to write more code than you would normally (other than the annotations themselves).
The annotations just remind you about code you forgot to write.
If you am passing in a value to one method that requires @NotNull parameters,
and that value was obtained by another method whose return value is marked @NotNull, you need not write an explicit null check. That saves
you coding and reduces the need for overly conservative defensive programming.
Of course you are not obligated to mark every return, parameter and variable with an annotation. The unmarked
ones you deal with at run time with a NullPointerException and/or with explicit
null-checking code.
This sounds simple enough but there are quite a number of steps and complications to getting it to work:
- The @Nullable and @NotNull annotations are
an open source feature of the IntelliJ IDE (Integrated Development Environment), not a feature of the Java language.
Annotations in general are of course built into Java. JetBrains have offered them to Oracle to include in
standard Java, but Oracle has not yet accepted them.
- The class files to implement org.jetbrains.annotations.Nullable live in
X:\Program Files (x86)\JetBrains\IntelliJ IDEA 12.1\lib\annotations.jar
and F:\Program Files (x86)\JetBrains\IntelliJ IDEA 12.1\redist\annotations.jar.
- You have to configure the feature to work in IntelliJ. You must configure J:\Program
Files (x86)\JetBrains\IntelliJ IDEA 12.1\redist\annotations.jar as one of the libraries accessible to
your module. This will only apply to your 1.5+ targets.
- In the project panel, click the name of your project. This is the tricky
part. You must click the project, not the module to configure the module.
- Click Module Settings.
- Click Project.
- On the left, click modules.
- Click the name of one of your modules from the middle column.
- Click Dependencies
- Click add.
- Click Single-entry module library
- Navigate to J:\Program Files (x86)\JetBrains\IntelliJ IDEA
12.1\redist\annotations.jar
- Click OK.
- Click OK.
- Strange as it sounds to the novice programmer, but it is also possible to store your annotations separately
from the source code, though the IntelliJ IDE
will display them as if they were embedded. This ability in not peculiar to IntelliJ. log4j,� SLF4J, XStream,
Spring, mysql-connector-j, commons-lang, junit… all store information about the code separately from the
source code, many using the annotation mechanism. JSR-305 on Annotations for Software Defect Detection is
nothing but annotation.
- To make the annotations available to your JDK (Java Development Kit)
used by IntelliJ to compile your code (as distinct from the JRE (Java Runtime Environment)
it uses to run the IDE), or to let ANT (A Neat Tool)
compile outside IntelliJ, you will need to install annotations.jar in your own
various ext directories. Theoretically you don’t need to put in all of them,
but I find it simpler to do so.
where to look for ext directories :
At this point all will work fine, except that if you reorganize your imports
the following lines will disappear:
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable
What you have to do now is configure the auto-import function to ignore these imports:
- Click File.
- Click Settings.
- Click +Editor.
- Click Auto Import.
- Under Exclude from import and completion, click Add.
- Type org.jetbrains.annotations.NotNull
- Click Add again.
- Type org.jetbrains.annotations.Nullable
- Click OK.
- If you give your code to other people, their compiler won’t understand the annotations. What do you
do to allow others to deal with your annotations? In general javac.exe just ignores
annotations it does not recognise. Thus others will need your J:\Program Files
(x86)\JetBrains\IntelliJ IDEA 12.1\redist\annotations.jar. You would have to bundle it with your source
code distributions. They need to install annotations.jar in their
JDK
ext directories e.g.
where to look for ext directories :
- Now insert some imports and annotations in your source code, and build.
Classpath Method
Mark Vedder said there is a much shorter way to accomplish this, that works by adding the annotations.jar to the classpath. I like to avoid using the classpath, since it so many cooks
fiddle with it.
- Type the @Nullable or @NotNull annotations
in your source code.
- Hit alt+enter to invoke quick fix and select Add
'annotations.jar' to classpath or Add Maven dependency if it’s
a Maven project.
- Click OK to the dialog and continue working.
- I suspect you still have to do some of the above steps in the long method.
Puzzles
- Does the IntelliJ IDE
evaluate the annotations or does Javac? or both?
- What is the best way to stop the imports from disappearing?
- What do you have to do so other people who do not own IntelliJ can build?
- Can people without IntelliJ use the annotations? If so, will they be evaluated or ignored?