1. Overview
Starting with Spring 5, we now have access to an interesting feature helping us write safer code. This feature is called null safety, a group of annotations working like a safeguard that watches out for potential null references.
Rather than letting us get away with unsafe code, the null-safety feature produces warnings at compile time. Such warnings may prevent catastrophic null pointer exceptions (NPEs) at runtime.
2. The @NonNull Annotation
The @NonNull annotation is the most important among all the annotations of the null-safety feature. We can use this annotation to declare non-null constraint anywhere an object reference is expected: a field, a method parameter or a method’s return value.
Suppose we have a class named Person:
public class Person {
private String fullName;
void setFullName(String fullName) {
if (fullName != null && fullName.isEmpty()) {
fullName = null;
}
this.fullName = fullName;
}
// getter
}
This class definition is valid but has a defect – the fullName field may be set to null. If this happens, we could end up with an NPE when working with fullName.
The Spring null-safety feature enables tools to report such a danger. For instance, if we write code in IntelliJ IDEA and decorate the fullName field with the @NonNull annotation, we’ll see a warning:
Thanks to this indication, we’re aware of the problem in advance and able to take appropriate action to avoid a runtime failure.
3. The @NonNullFields Annotation
The @NonNull annotation is helpful in guaranteeing null safety. However, we would pollute the whole code base if adorning all non-null fields with this annotation.
We can avoid the abuse of @NonNull with another annotation – @NonNullFields. This annotation is applicable at the package level, notifying our development tools that all fields in the annotated package are, by default, non-null.
For the @NonNullFields annotation to kick in, we need to create a file named package-info.java in the root directory of the package and annotate the package with @NonNullFields:
@NonNullFields
package org.baeldung.nullibility;
Let’s declare another property in the Person class called nickName:
package org.baeldung.nullibility;
// import statements
public class Person {
private String nickName;
void setNickName(@Nullable String nickName) {
if (nickName != null && nickName.isEmpty()) {
nickName = null;
}
this.nickName = nickName;
}
// other declarations
}
This time, we don’t embellish the nickName field with @NonNull but still see a similar caveat:
The @NonNullFields annotation makes our code less verbose while ensuring the same level of safety that @NonNull provides.
4. The @Nullable Annotation
The @NonNullFields annotation is generally preferable to @NonNull as it helps reduce boilerplate. At times we want to exempt some fields from the non-null constraint specified at the package level.
Let’s go back to the nickName field and decorate it with the @Nullable annotation:
@Nullable
private String nickName;
The warning we saw before is gone now:
In this situation, we used the @Nullable annotation to override the semantics of @NonNullFields on a field.
5. The @NonNullApi Annotation
The @NonNullFields annotation only applies to, as its name suggests, fields. If we want to have the same impact on the methods’ parameters and return values, we’ll need @NonNullApi.
As with @NonNullFields, we must specify the @NonNullApi annotation in the package-info.java file:
@NonNullApi
package org.baeldung.nullibility;
Let’s define a getter for the nickName field:
package org.baeldung.nullibility;
// import statements
public class Person {
@Nullable
private String nickName;
String getNickName() {
return nickName;
}
// other declarations
}
With the @NonNullApi annotation in effect, a warning is issued about a possibly null value produced by the getNickName method:
Notice that just like the @NonNullFields annotation, we can override the @NonNullApi at the method level with the @Nullable annotation.
6. Conclusion
Spring null safety is a great feature that helps diminish the possibility of NPEs. However, there are two important points we need to beware of while using this feature:
- It’s only usable in a supporting development tool, such as IntelliJ IDEA
- It doesn’t enforce null checks at runtime – we still need to write code ourselves to avert NPEs
The source code for this tutorial can be found on GitHub.