Refine null-safety documentation terms
Closes gh-34982
This commit is contained in:
parent
45ba4ace39
commit
0b14d676cc
|
@ -1,15 +1,15 @@
|
|||
[[null-safety]]
|
||||
= Null-safety
|
||||
|
||||
Although Java does not let you express null-safety with its type system, the Spring Framework codebase is annotated with
|
||||
https://jspecify.dev/docs/start-here/[JSpecify] annotations to declare the nullness of APIs, fields and related type
|
||||
usages. Reading the https://jspecify.dev/docs/user-guide/[JSpecify user guide] is highly recommended in order to get
|
||||
familiar with those annotations and semantics.
|
||||
Although Java does not let you express nullness markers with its type system yet, the Spring Framework codebase is
|
||||
annotated with https://jspecify.dev/docs/start-here/[JSpecify] annotations to declare the nullability of its APIs,
|
||||
fields and related type usages. Reading the https://jspecify.dev/docs/user-guide/[JSpecify user guide] is highly
|
||||
recommended in order to get familiar with those annotations and semantics.
|
||||
|
||||
The primary goal of this explicit null-safety arrangement is to prevent `NullPointerException` to be thrown at runtime via
|
||||
build time checks and to turn explicit nullness into a way to express the possible absence of value. It is useful in
|
||||
both Java by leveraging some tooling (https://github.com/uber/NullAway[NullAway] or IDEs supporting null-safety
|
||||
annotations such as IntelliJ IDEA or Eclipse) and Kotlin where JSpecify annotations are automatically translated to
|
||||
The primary goal of this null-safety arrangement is to prevent `NullPointerException` to be thrown at runtime via build
|
||||
time checks and to turn explicit nullability into a way to express the possible absence of value. It is useful in both
|
||||
Java by leveraging some tooling (https://github.com/uber/NullAway[NullAway] or IDEs supporting JSpecify annotations
|
||||
such as IntelliJ IDEA for example) and Kotlin where JSpecify annotations are automatically translated to
|
||||
{kotlin-docs}/null-safety.html[Kotlin's null safety].
|
||||
|
||||
The {spring-framework-api}/core/Nullness.html[`Nullness` Spring API] can be used at runtime to detect the nullness of a
|
||||
|
@ -21,7 +21,7 @@ package).
|
|||
== Annotating libraries with JSpecify annotations
|
||||
|
||||
As of Spring Framework 7, the Spring Framework codebase leverages JSpecify annotations to expose null-safe APIs and
|
||||
to check the consistency of those null-safety declarations with https://github.com/uber/NullAway[NullAway] as part of
|
||||
to check the consistency of those nullability declarations with https://github.com/uber/NullAway[NullAway] as part of
|
||||
its build. It is recommended for each library depending on Spring Framework (Spring portfolio projects), as
|
||||
well as other libraries related to the Spring ecosystem (Reactor, Micrometer and Spring community projects), to do the
|
||||
same.
|
||||
|
@ -29,18 +29,18 @@ same.
|
|||
[[null-safety-applications]]
|
||||
== Leveraging JSpecify annotations in Spring applications
|
||||
|
||||
Developing applications with IDEs supporting null-safety annotations, such as IntelliJ IDEA or Eclipse, will provide
|
||||
warnings in Java and errors in Kotlin when the null-safety contracts are not honored, allowing Spring application
|
||||
developers to refine their null handling to prevent `NullPointerException` to be thrown at runtime.
|
||||
Developing applications with IDEs supporting nullness annotations will provide warnings in Java and errors in Kotlin
|
||||
when the nullability contracts are not honored, allowing Spring application developers to refine their null handling to
|
||||
prevent `NullPointerException` to be thrown at runtime.
|
||||
|
||||
Optionally, Spring application developers can annotate their codebase and use https://github.com/uber/NullAway[NullAway]
|
||||
to enforce null-safety during build time at application level.
|
||||
Optionally, Spring application developers can annotate their codebase and use build plugins like
|
||||
https://github.com/uber/NullAway[NullAway] to enforce null-safety during build time at application level.
|
||||
|
||||
[[null-safety-guidelines]]
|
||||
== Guidelines
|
||||
|
||||
The purpose of this section is to share some guidelines proposed for specifying explicitly the nullness of Spring-related
|
||||
libraries or applications.
|
||||
The purpose of this section is to share some guidelines proposed for specifying explicitly the nullability of
|
||||
Spring-related libraries or applications.
|
||||
|
||||
|
||||
[[null-safety-guidelines-jspecify]]
|
||||
|
@ -62,7 +62,7 @@ import org.jspecify.annotations.NullMarked;
|
|||
|
||||
In the various Java files belonging to the package, nullable type usages are defined explicitly with
|
||||
https://jspecify.dev/docs/api/org/jspecify/annotations/Nullable.html[`@Nullable`]. It is recommended that this
|
||||
annotation is specified just before the related type.
|
||||
annotation is specified just before the related type on the same line.
|
||||
|
||||
For example, for a field:
|
||||
|
||||
|
@ -81,9 +81,8 @@ public static @Nullable String buildMessage(@Nullable String message,
|
|||
}
|
||||
----
|
||||
|
||||
When overriding a method, nullness annotations are not inherited from the superclass method. That means those
|
||||
nullness annotations should be repeated if you just want to override the implementation and keep the same API
|
||||
nullness.
|
||||
When overriding a method, JSpecify annotations are not inherited from the superclass method. That means they should be
|
||||
repeated if you just want to override the implementation and keep the same nullability.
|
||||
|
||||
With arrays and varargs, you need to be able to differentiate the nullness of the elements from the nullness of
|
||||
the array itself. Pay attention to the syntax
|
||||
|
@ -111,10 +110,10 @@ typical use cases.
|
|||
|
||||
The recommended configuration is:
|
||||
|
||||
- `NullAway:OnlyNullMarked=true` in order to perform nullness checks only for packages annotated with `@NullMarked`.
|
||||
- `NullAway:OnlyNullMarked=true` in order to perform nullability checks only for packages annotated with `@NullMarked`.
|
||||
- `NullAway:CustomContractAnnotations=org.springframework.lang.Contract` which makes NullAway aware of the
|
||||
{spring-framework-api}/lang/Contract.html[@Contract] annotation in the `org.springframework.lang` package which
|
||||
can be used to express complementary semantics to avoid non-relevant null-safety warnings in your codebase.
|
||||
can be used to express complementary semantics to avoid non-relevant warnings in your codebase.
|
||||
|
||||
A good example of `@Contract` benefits is
|
||||
{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.
|
|||
|
||||
==== Warnings suppression
|
||||
|
||||
There are a few valid use cases where NullAway will wrongly detect nullness problems. In such case, it is recommended
|
||||
There are a few valid use cases where NullAway will wrongly detect nullability problems. In such case, it is recommended
|
||||
to suppress related warnings and to document the reason:
|
||||
|
||||
- `@SuppressWarnings("NullAway.Init")` at field, constructor or class level can be used to avoid unnecessary warnings
|
||||
due to the lazy initialization of fields, for example due to a class implementing
|
||||
{spring-framework-api}/beans/factory/InitializingBean.html[`InitializingBean`].
|
||||
- `@SuppressWarnings("NullAway") // Dataflow analysis limitation` can be used when NullAway dataflow analysis is not
|
||||
able to detect that the path involving a nullness problem will never happen.
|
||||
able to detect that the path involving a nullability problem will never happen.
|
||||
- `@SuppressWarnings("NullAway") // Lambda` can be used when NullAway does not take into account assertions performed
|
||||
outside of a lambda for the code path within the lambda.
|
||||
- `@SuppressWarnings("NullAway") // Reflection` can be used for some reflection operations that are known returning
|
||||
non-null values even if that can't be expressed by the API.
|
||||
- `@SuppressWarnings("NullAway") // Well-known map keys` can be used when `Map#get` invocations are done with keys known
|
||||
to be present and non-null related values inserted previously.
|
||||
- `@SuppressWarnings("NullAway") // Overridden method does not define nullness` can be used when the super class does
|
||||
not define nullness (typically when the super class is coming from a dependency).
|
||||
- `@SuppressWarnings("NullAway") // Overridden method does not define nullability` can be used when the super class does
|
||||
not define nullability (typically when the super class is coming from a dependency).
|
||||
|
||||
|
||||
[[null-safety-migrating]]
|
||||
|
@ -160,9 +159,9 @@ introduced in Spring Framework 5 when JSpecify did not exist and the best option
|
|||
but widespread JSR) meta-annotations. They are deprecated as of Spring Framework 7 in favor of
|
||||
https://jspecify.dev/docs/start-here/[JSpecify] annotations, which provide significant enhancements such as properly
|
||||
defined specifications, a canonical dependency with no split-package issue, better tooling, better Kotlin integration
|
||||
and the capability to specify the nullness more precisely for more use cases.
|
||||
and the capability to specify the nullability more precisely for more use cases.
|
||||
|
||||
A key difference is that Spring null-safety annotations, following JSR 305 semantics, apply to fields,
|
||||
A key difference is that Spring deprecated null-safety annotations, following JSR 305 semantics, apply to fields,
|
||||
parameters and return values while JSpecify annotations apply to type usages. This subtle difference
|
||||
is in practice pretty significant, as it allows for example to differentiate the nullness of elements from the
|
||||
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
|
|||
`@Nullable Object[] array` with Spring annotations needs to be changed to `Object @Nullable [] array` with JSpecify
|
||||
annotations. Same for varargs.
|
||||
|
||||
It is also recommended to move field and return value annotations closer to the type, for example:
|
||||
It is also recommended to move field and return value annotations closer to the type on the same line, for example:
|
||||
|
||||
- For fields, instead of `@Nullable private String field` with Spring annotations, use `private @Nullable String field`
|
||||
with JSpecify annotations.
|
||||
|
|
Loading…
Reference in New Issue