Skip to content

Spring Null-safety annotations

1. Overview

In this article, we will discuss more on Spring Null-safety annotations along with few examples.

Null-Safety prevents the code that would cause NullPointerException from compilation and forces you to make an explicit decision to prevent it or not to avoid NullPointerExceptions at runtime.

2. Null safety

Java doesn’t enforce Null-safety. But after Java 8, java.util.Optional is included in the language to achieve null safety. Unlike Kotlin, the Java language doesn’t enforce the use of Optional. However, you can use Optional to achieve null safety if you want to.

Besides Optional, Spring 5 also provides a set of annotations to let you declare the nullability of fields and APIs. These annotations are available in the package org.springframework.lang and you can import the annotations from this package.

Annotations are:

  • @Nullable
  • @NotNull
  • @NonNullApi
  • @NonNullFields

But these annotations show compile-time errors only in IntelliJ IDEA (v10.5 and above). Refer to More flexible and configurable @Nullable/@NotNull annotations blog post of Jetbrains.

2.1. @Nullable annotation

The @Nullable annotation helps to identify:

  • Method that can return null
  • Variables (fields, local variables, and parameters) that can be null

Let’s take an example where a variable might be null.

Suppose we want to get user feedback on a product and take necessary action. The user feedback form involves three entries: name, email address, comments.

As a first step, we had to get the user’s comment and check for any SQL injection. Sometimes, the user might submit the form with no comments. In such a scenario, the comment would be null.

It would throw NullPointerException if we try to parse the comment without checking for null. The below main function fetches all the feedback submissions using the function generateFeedback(). It then processes each feedback using listIterator. Here, the code is not informed that comment can be null and doesn’t have any null check in place.

public class Runner {
    public static void main(String[] args) throws InterruptedException {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
        context.registerShutdownHook();
        ArrayList<Feedback> list = generateFeedback(); 
        ListIterator<Feedback> iterator = list.listIterator();
        while (iterator.hasNext()) {
        	Feedback feedback = (Feedback) iterator.next();
        	String comment = feedback.comment;
        	if (comment.contains(invalidChars)) {

        	}
        }
    }
}
class Feedback {
	String name;
	String emailAddress;
	String comment;
	
	Feedback(String name, String emailAddress, String feedback) {
		this.name = name;
		this.emailAddress = emailAddress;
		this.comment = feedback;
	}
	public String getFeedback() {
		return comment;
	}
}

The above code will throw NullPointerException at runtime if the comment is null. To avoid this, we can use @Nullable annotation to show the caller that this comment variable can be null.

class Feedback {
	String name;
	String emailAddress;
	@Nullable
	String comment;
	
	Feedback(String name, String emailAddress, String feedback) {
		this.name = name;
		this.emailAddress = emailAddress;
		this.comment = feedback;
	}
	public String getFeedback() {
		return comment;
	}
}

2.2. @NonNull annotation

The @NotNull annotation helps to declare that:

  • A method can not return null
  • Variables (fields, local variables, and parameters) cannot hold a null value

Let’s take an example to understand this. We have declared employeeId as NonNull, meaning it can’t accept null values. So when you try to pass a null value, IntelliJ will throw compile-time error.

class Employee {
	String name;
	@NonNull
	String employeeId;
	
	Employee(String name, @NonNull String employeeId) {
		this.name = name;
		this.employeeId = employeeId;
	}
}

public static Employee generateFeedback() {
    	Employee employee = new Employee("Chris", null);
    	return employee;
    }

2.3. Package level Null safety annotations.

Suppose, you want the entire package methods and variables to be not null, then it would require considerable effort to add @NonNull to every parameter and return type in the package. It could also lead to manual errors.

To avoid this, Spring introduced @NonNullApi and @NonNullFields to annotate the entire package as non-null.

  • @NonNullApi – To annotate method parameters and return types as not null
  • @NonNullFields – To annotate fields as not null

Okay. So how do we annotate the entire package as non-null? Create a package-info.java file in the intended package. Then, annotate the package as @NonNullApi or @NonNullFields based on your need as shown in the below images.

package-info.json inside package
Package-info.java file in the package
Package level NonNull annotations
Package level NonNull annotations

Here, we declared the entire package as not null. But in some scenarios. Few fields or methods can be null and shouldn’t be declared as Not null. In that case, use @Nullable annotation to declare the variable or method can be null.

3. Conclusion

In this article, we discussed the Null-safety of the Spring framework with examples. As mentioned, these annotations work as expected with IntelliJ IDEA and throw compile time errors.

See our other articles on Spring AOP.

1 thought on “Spring Null-safety annotations”

Leave a Reply

Your email address will not be published. Required fields are marked *