Null Safety with JSpecify
Spring Framework 7 and Spring Boot 4 annotate the whole portfolio with
JSpecify. Your IDE and build can now tell you where a null can
appear — before it appears at runtime.
The four annotations
| Annotation | Meaning |
|---|---|
@NullMarked | in this scope everything is non-null unless marked otherwise |
@Nullable | this type may be null |
@NonNull | this type is not null (rarely needed inside @NullMarked) |
@NullUnmarked | opt a scope back out |
Mark your packages
src/main/java/com/example/demo/package-info.java:
Everything in the package is now non-null by default — one file per package, no annotations sprinkled over the code.
Then annotate the exceptions
@Nullable goes on the type, so generics work as expected:
What you get
- IDE warnings where a nullable value is dereferenced
- Kotlin sees Spring APIs as proper platform-free types
- static analysis — NullAway can fail the build on a violation
Note
These annotations are compile-time only. Nothing is checked at runtime — the payoff is in the tools.
Optional or @Nullable?
| Use | Where |
|---|---|
Optional<T> | return values of query-style methods, stream chains |
@Nullable T | fields, parameters, hot paths, overrides |
Never use Optional as a parameter type or a field.
Practical rules
- prefer designs where
nullnever appears: empty collections, default objects,Optional - validate at the edge (
@Valid), so the inside of the app can assume non-null Objects.requireNonNull(x, "x")for constructor arguments that must be present- do not annotate
@Nullableon something you then dereference unchecked
★ Exercises
- Add a
package-info.javawith@NullMarkedto your service package. - Mark one repository lookup
@Nullableand see what the IDE says at the call site. - Rewrite that method to return
Optional<Book>— which reads better here? - Explain the difference between
List<@Nullable String>and@Nullable List<String>. - Add
Objects.requireNonNullto a constructor and write a test for it.