1
1
[[null-safety]]
2
2
= Null-safety
3
3
4
- Although Java does not let you express null-safety with its type system, the Spring Framework codebase is annotated with
5
- https://jspecify.dev/docs/start-here/[JSpecify] annotations to declare the nullness of APIs, fields and related type
6
- usages. Reading the https://jspecify.dev/docs/user-guide/[JSpecify user guide] is highly recommended in order to get
7
- familiar with those annotations and semantics.
8
-
9
- The primary goal of this explicit null-safety arrangement is to prevent `NullPointerException` to be thrown at runtime via
10
- build time checks and to turn explicit nullness into a way to express the possible absence of value. It is useful in
11
- both Java by leveraging some tooling (https://github.com/uber/NullAway[NullAway] or IDEs supporting null-safety
12
- annotations such as IntelliJ IDEA or Eclipse ) and Kotlin where JSpecify annotations are automatically translated to
4
+ Although Java does not let you express nullness markers with its type system yet , the Spring Framework codebase is
5
+ annotated with https://jspecify.dev/docs/start-here/[JSpecify] annotations to declare the nullability of its APIs,
6
+ fields and related type usages. Reading the https://jspecify.dev/docs/user-guide/[JSpecify user guide] is highly
7
+ recommended in order to get familiar with those annotations and semantics.
8
+
9
+ The primary goal of this null-safety arrangement is to prevent `NullPointerException` to be thrown at runtime via build
10
+ time checks and to turn explicit nullability into a way to express the possible absence of value. It is useful in both
11
+ Java by leveraging some tooling (https://github.com/uber/NullAway[NullAway] or IDEs supporting JSpecify annotations
12
+ such as IntelliJ IDEA for example ) and Kotlin where JSpecify annotations are automatically translated to
13
13
{kotlin-docs}/null-safety.html[Kotlin's null safety].
14
14
15
15
The {spring-framework-api}/core/Nullness.html[`Nullness` Spring API] can be used at runtime to detect the nullness of a
@@ -21,26 +21,26 @@ package).
21
21
== Annotating libraries with JSpecify annotations
22
22
23
23
As of Spring Framework 7, the Spring Framework codebase leverages JSpecify annotations to expose null-safe APIs and
24
- to check the consistency of those null-safety declarations with https://github.com/uber/NullAway[NullAway] as part of
24
+ to check the consistency of those nullability declarations with https://github.com/uber/NullAway[NullAway] as part of
25
25
its build. It is recommended for each library depending on Spring Framework (Spring portfolio projects), as
26
26
well as other libraries related to the Spring ecosystem (Reactor, Micrometer and Spring community projects), to do the
27
27
same.
28
28
29
29
[[null-safety-applications]]
30
30
== Leveraging JSpecify annotations in Spring applications
31
31
32
- Developing applications with IDEs supporting null-safety annotations, such as IntelliJ IDEA or Eclipse, will provide
33
- warnings in Java and errors in Kotlin when the null-safety contracts are not honored, allowing Spring application
34
- developers to refine their null handling to prevent `NullPointerException` to be thrown at runtime.
32
+ Developing applications with IDEs supporting nullness annotations will provide warnings in Java and errors in Kotlin
33
+ when the nullability contracts are not honored, allowing Spring application developers to refine their null handling to
34
+ prevent `NullPointerException` to be thrown at runtime.
35
35
36
- Optionally, Spring application developers can annotate their codebase and use https://github.com/uber/NullAway[NullAway]
37
- to enforce null-safety during build time at application level.
36
+ Optionally, Spring application developers can annotate their codebase and use build plugins like
37
+ https://github.com/uber/NullAway[NullAway] to enforce null-safety during build time at application level.
38
38
39
39
[[null-safety-guidelines]]
40
40
== Guidelines
41
41
42
- The purpose of this section is to share some guidelines proposed for specifying explicitly the nullness of Spring-related
43
- libraries or applications.
42
+ The purpose of this section is to share some guidelines proposed for specifying explicitly the nullability of
43
+ Spring-related libraries or applications.
44
44
45
45
46
46
[[null-safety-guidelines-jspecify]]
@@ -62,7 +62,7 @@ import org.jspecify.annotations.NullMarked;
62
62
63
63
In the various Java files belonging to the package, nullable type usages are defined explicitly with
64
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.
65
+ annotation is specified just before the related type on the same line .
66
66
67
67
For example, for a field:
68
68
@@ -81,9 +81,8 @@ public static @Nullable String buildMessage(@Nullable String message,
81
81
}
82
82
----
83
83
84
- When overriding a method, nullness annotations are not inherited from the superclass method. That means those
85
- nullness annotations should be repeated if you just want to override the implementation and keep the same API
86
- nullness.
84
+ When overriding a method, JSpecify annotations are not inherited from the superclass method. That means they should be
85
+ repeated if you just want to override the implementation and keep the same nullability.
87
86
88
87
With arrays and varargs, you need to be able to differentiate the nullness of the elements from the nullness of
89
88
the array itself. Pay attention to the syntax
@@ -111,10 +110,10 @@ typical use cases.
111
110
112
111
The recommended configuration is:
113
112
114
- - `NullAway:OnlyNullMarked=true` in order to perform nullness checks only for packages annotated with `@NullMarked`.
113
+ - `NullAway:OnlyNullMarked=true` in order to perform nullability checks only for packages annotated with `@NullMarked`.
115
114
- `NullAway:CustomContractAnnotations=org.springframework.lang.Contract` which makes NullAway aware of the
116
115
{spring-framework-api}/lang/Contract.html[@Contract] annotation in the `org.springframework.lang` package which
117
- can be used to express complementary semantics to avoid non-relevant null-safety warnings in your codebase.
116
+ can be used to express complementary semantics to avoid non-relevant warnings in your codebase.
118
117
119
118
A good example of `@Contract` benefits is
120
119
{spring-framework-api}/util/Assert.html#notNull(java.lang.Object,java.lang.String)[`Assert#notnull`] which is annotated
@@ -131,22 +130,22 @@ generates no warning with the recommended configuration mentioned above.
131
130
132
131
==== Warnings suppression
133
132
134
- There are a few valid use cases where NullAway will wrongly detect nullness problems. In such case, it is recommended
133
+ There are a few valid use cases where NullAway will wrongly detect nullability problems. In such case, it is recommended
135
134
to suppress related warnings and to document the reason:
136
135
137
136
- `@SuppressWarnings("NullAway.Init")` at field, constructor or class level can be used to avoid unnecessary warnings
138
137
due to the lazy initialization of fields, for example due to a class implementing
139
138
{spring-framework-api}/beans/factory/InitializingBean.html[`InitializingBean`].
140
139
- `@SuppressWarnings("NullAway") // Dataflow analysis limitation` can be used when NullAway dataflow analysis is not
141
- able to detect that the path involving a nullness problem will never happen.
140
+ able to detect that the path involving a nullability problem will never happen.
142
141
- `@SuppressWarnings("NullAway") // Lambda` can be used when NullAway does not take into account assertions performed
143
142
outside of a lambda for the code path within the lambda.
144
143
- `@SuppressWarnings("NullAway") // Reflection` can be used for some reflection operations that are known returning
145
144
non-null values even if that can't be expressed by the API.
146
145
- `@SuppressWarnings("NullAway") // Well-known map keys` can be used when `Map#get` invocations are done with keys known
147
146
to be present and non-null related values inserted previously.
148
- - `@SuppressWarnings("NullAway") // Overridden method does not define nullness ` can be used when the super class does
149
- not define nullness (typically when the super class is coming from a dependency).
147
+ - `@SuppressWarnings("NullAway") // Overridden method does not define nullability ` can be used when the super class does
148
+ not define nullability (typically when the super class is coming from a dependency).
150
149
151
150
152
151
[[null-safety-migrating]]
@@ -160,9 +159,9 @@ introduced in Spring Framework 5 when JSpecify did not exist and the best option
160
159
but widespread JSR) meta-annotations. They are deprecated as of Spring Framework 7 in favor of
161
160
https://jspecify.dev/docs/start-here/[JSpecify] annotations, which provide significant enhancements such as properly
162
161
defined specifications, a canonical dependency with no split-package issue, better tooling, better Kotlin integration
163
- and the capability to specify the nullness more precisely for more use cases.
162
+ and the capability to specify the nullability more precisely for more use cases.
164
163
165
- A key difference is that Spring null-safety annotations, following JSR 305 semantics, apply to fields,
164
+ A key difference is that Spring deprecated null-safety annotations, following JSR 305 semantics, apply to fields,
166
165
parameters and return values while JSpecify annotations apply to type usages. This subtle difference
167
166
is in practice pretty significant, as it allows for example to differentiate the nullness of elements from the
168
167
nullness of arrays/varargs as well as defining the nullness of generic types.
@@ -171,7 +170,7 @@ That means array and varargs null-safety declarations have to be updated to keep
171
170
`@Nullable Object[] array` with Spring annotations needs to be changed to `Object @Nullable [] array` with JSpecify
172
171
annotations. Same for varargs.
173
172
174
- It is also recommended to move field and return value annotations closer to the type, for example:
173
+ It is also recommended to move field and return value annotations closer to the type on the same line , for example:
175
174
176
175
- For fields, instead of `@Nullable private String field` with Spring annotations, use `private @Nullable String field`
177
176
with JSpecify annotations.
0 commit comments