Skip to content

Commit 701e034

Browse files
committed
Improve null-safety documentation related to TYPE_USE
This commit refines the null-safety documentation to document more explicitly the code style guidelines related to `@Target(ElementType.TYPE_USE)`. Closes gh-35098
1 parent 0f495d3 commit 701e034

File tree

1 file changed

+41
-14
lines changed

1 file changed

+41
-14
lines changed

framework-docs/modules/ROOT/pages/core/null-safety.adoc

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ Spring-related libraries or applications.
4646
[[null-safety-guidelines-jspecify]]
4747
=== JSpecify
4848

49-
The key points to understand are that the nullness of types is unknown in Java by default and that non-null type
50-
usage is by far more frequent than nullable usage. In order to keep codebases readable, we typically want to define
49+
==== Defaults to non-null
50+
51+
A key point to understand is that the nullness of types is unknown by default in Java and that non-null type
52+
usages are by far more frequent than nullable usages. In order to keep codebases readable, we typically want to define
5153
by default that type usage is non-null unless marked as nullable for a specific scope. This is exactly the purpose of
5254
https://jspecify.dev/docs/api/org/jspecify/annotations/NullMarked.html[`@NullMarked`] which is typically set in Spring
5355
projects at the package level via a `package-info.java` file, for example:
@@ -60,9 +62,17 @@ package org.springframework.core;
6062
import org.jspecify.annotations.NullMarked;
6163
----
6264

63-
In the various Java files belonging to the package, nullable type usage is defined explicitly with
64-
https://jspecify.dev/docs/api/org/jspecify/annotations/Nullable.html[`@Nullable`]. It is recommended that this
65-
annotation is specified just before the related type on the same line.
65+
==== Explicit nullability
66+
67+
In `@NullMarked` code, nullable type usages are defined explicitly with
68+
https://jspecify.dev/docs/api/org/jspecify/annotations/Nullable.html[`@Nullable`].
69+
70+
A key difference between JSpecify `@Nullable` / `@NonNull` annotations and most other variants is that they are
71+
meta-annotated with `@Target(ElementType.TYPE_USE)`, so they apply only to type usages. This impacts where such
72+
annotations should be placed, either to comply with
73+
https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.4[related Java specifications] or to follow code
74+
style best practices. From a style perspective, it is recommended to embrace the type-use nature of those annotations by placing them on the
75+
same line than the annotated type.
6676

6777
For example, for a field:
6878

@@ -75,8 +85,8 @@ Or for method parameters and method return types:
7585

7686
[source,java,subs="verbatim,quotes"]
7787
----
78-
public static @Nullable String buildMessage(@Nullable String message,
79-
@Nullable Throwable cause) {
88+
public @Nullable String buildMessage(@Nullable String message,
89+
@Nullable Throwable cause) {
8090
// ...
8191
}
8292
----
@@ -88,24 +98,41 @@ method. That means the JSpecify annotations should be copied to the overriding m
8898
you want to override the implementation and keep the same nullability semantics.
8999
====
90100

101+
https://jspecify.dev/docs/api/org/jspecify/annotations/NonNull.html[`@NonNull`] and
102+
https://jspecify.dev/docs/api/org/jspecify/annotations/NullUnmarked.html[`@NullUnmarked`] should rarely be needed for
103+
typical use cases.
104+
105+
==== Arrays and varargs
106+
91107
With arrays and varargs, you need to be able to differentiate the nullness of the elements from the nullness of
92108
the array itself. Pay attention to the syntax
93109
https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.4[defined by the Java specification] which may be
94-
initially surprising:
110+
initially surprising. For example, in `@NullMarked` code:
95111

96112
- `@Nullable Object[] array` means individual elements can be null but the array itself cannot.
97113
- `Object @Nullable [] array` means individual elements cannot be null but the array itself can.
98114
- `@Nullable Object @Nullable [] array` means both individual elements and the array can be null.
99115

116+
==== Generics
117+
118+
JSpecify annotations applies to generics as well. For example, in `@NullMarked` code:
119+
120+
- `List<String>` means a list of non-null elements (equivalent of `List<@NonNull String>`)
121+
- `List<@Nullable String>` means a list of nullable elements
122+
123+
Things are a bit more complicated when you are declaring generic types or generic methods, see related
124+
https://jspecify.dev/docs/user-guide/#generics[JSpecify generics documentation] for more details.
125+
126+
WARNING: Generic types and generic methods nullability https://github.com/uber/NullAway/issues?q=is%3Aissue+is%3Aopen+label%3Ajspecify[is not yet fully supported by NullAway].
127+
128+
==== Nested and fully qualified types
129+
100130
The Java specification also enforces that annotations defined with `@Target(ElementType.TYPE_USE)` like JSpecify
101131
`@Nullable` should be specified after the last `.` with inner or fully qualified types:
102132

103-
- `Cache.@Nullable ValueWrapper`
104-
- `jakarta.validation.@Nullable Validator`
133+
- `Cache.@Nullable ValueWrapper`
134+
- `jakarta.validation.@Nullable Validator`
105135

106-
https://jspecify.dev/docs/api/org/jspecify/annotations/NonNull.html[`@NonNull`] and
107-
https://jspecify.dev/docs/api/org/jspecify/annotations/NullUnmarked.html[`@NullUnmarked`] should rarely be needed for
108-
typical use cases.
109136

110137
[[null-safety-guidelines-nullaway]]
111138
=== NullAway
@@ -126,7 +153,7 @@ parameter cannot be null after a successful invocation of `Assert.notNull()`.
126153

127154
Optionally, it is possible to set `NullAway:JSpecifyMode=true` to enable
128155
https://github.com/uber/NullAway/wiki/JSpecify-Support[checks on the full JSpecify semantics], including annotations on
129-
generic types. Be aware that this mode is
156+
arrays, varargs and generics. Be aware that this mode is
130157
https://github.com/uber/NullAway/issues?q=is%3Aissue+is%3Aopen+label%3Ajspecify[still under development] and requires
131158
using JDK 22 or later (typically combined with the `--release` Java compiler flag to configure the
132159
expected baseline). It is recommended to enable the JSpecify mode only as a second step, after making sure the codebase

0 commit comments

Comments
 (0)