Browse Source

Improve wording

pull/35163/head
Sam Brannen 6 months ago
parent
commit
27072ccb87
  1. 46
      framework-docs/modules/ROOT/pages/core/null-safety.adoc

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

@ -42,14 +42,13 @@ https://github.com/uber/NullAway[NullAway] to enforce null-safety at the applica
The purpose of this section is to share some proposed guidelines for explicitly specifying the nullability of The purpose of this section is to share some proposed guidelines for explicitly specifying the nullability of
Spring-related libraries or applications. Spring-related libraries or applications.
[[null-safety-guidelines-jspecify]] [[null-safety-guidelines-jspecify]]
=== JSpecify === JSpecify
==== Defaults to non-null ==== Defaults to non-null
A key point to understand is that the nullness of types is unknown by default in Java and that non-null type A key point to understand is that the nullness of types is unknown by default in Java and that non-null type
usages are by far more frequent than nullable usages. In order to keep codebases readable, we typically want to define usage is by far more frequent than nullable usage. In order to keep codebases readable, we typically want to define
by default that type usage is non-null unless marked as nullable for a specific scope. This is exactly the purpose of by default that type usage is non-null unless marked as nullable for a specific scope. This is exactly the purpose of
https://jspecify.dev/docs/api/org/jspecify/annotations/NullMarked.html[`@NullMarked`] which is typically set in Spring https://jspecify.dev/docs/api/org/jspecify/annotations/NullMarked.html[`@NullMarked`] which is typically set in Spring
projects at the package level via a `package-info.java` file, for example: projects at the package level via a `package-info.java` file, for example:
@ -64,15 +63,15 @@ import org.jspecify.annotations.NullMarked;
==== Explicit nullability ==== Explicit nullability
In `@NullMarked` code, nullable type usages are defined explicitly with In `@NullMarked` code, nullable type usage is defined explicitly with
https://jspecify.dev/docs/api/org/jspecify/annotations/Nullable.html[`@Nullable`]. https://jspecify.dev/docs/api/org/jspecify/annotations/Nullable.html[`@Nullable`].
A key difference between JSpecify `@Nullable` / `@NonNull` annotations and most other variants is that they are A key difference between JSpecify `@Nullable` / `@NonNull` annotations and most other variants is that the JSpecify
meta-annotated with `@Target(ElementType.TYPE_USE)`, so they apply only to type usages. This impacts where such annotations are meta-annotated with `@Target(ElementType.TYPE_USE)`, so they apply only to type usage. This impacts
annotations should be placed, either to comply with where such annotations should be placed, either to comply with
https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.4[related Java specifications] or to follow code https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.4[related Java specifications] or to follow code
style best practices. From a style perspective, it is recommended to embrace the type-use nature of those annotations by placing them on the style best practices. From a style perspective, it is recommended to embrace the type-use nature of those annotations
same line than the annotated type. by placing them on the same line as and immediately preceding the annotated type.
For example, for a field: For example, for a field:
@ -109,26 +108,27 @@ the array itself. Pay attention to the syntax
https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.4[defined by the Java specification] which may be https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.4[defined by the Java specification] which may be
initially surprising. For example, in `@NullMarked` code: initially surprising. For example, in `@NullMarked` code:
- `@Nullable Object[] array` means individual elements can be null but the array itself cannot. - `@Nullable Object[] array` means individual elements can be `null` but the array itself cannot.
- `Object @Nullable [] array` means individual elements cannot be null but the array itself can. - `Object @Nullable [] array` means individual elements cannot be `null` but the array itself can.
- `@Nullable Object @Nullable [] array` means both individual elements and the array can be null. - `@Nullable Object @Nullable [] array` means both individual elements and the array can be `null`.
==== Generics ==== Generics
JSpecify annotations applies to generics as well. For example, in `@NullMarked` code: JSpecify annotations apply to generics as well. For example, in `@NullMarked` code:
- `List<String>` means a list of non-null elements (equivalent of `List<@NonNull String>`) - `List<String>` means a list of non-null elements (equivalent of `List<@NonNull String>`)
- `List<@Nullable String>` means a list of nullable elements - `List<@Nullable String>` means a list of nullable elements
Things are a bit more complicated when you are declaring generic types or generic methods, see related Things are a bit more complicated when you are declaring generic types or generic methods. See the related
https://jspecify.dev/docs/user-guide/#generics[JSpecify generics documentation] for more details. https://jspecify.dev/docs/user-guide/#generics[JSpecify generics documentation] for more details.
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]. WARNING: The nullability of generic types and generic methods
https://github.com/uber/NullAway/issues?q=is%3Aissue+is%3Aopen+label%3Ajspecify[is not yet fully supported by NullAway].
==== Nested and fully qualified types ==== Nested and fully qualified types
The Java specification also enforces that annotations defined with `@Target(ElementType.TYPE_USE)` like JSpecify The Java specification also enforces that annotations defined with `@Target(ElementType.TYPE_USE)` like JSpecify's
`@Nullable` should be specified after the last `.` with inner or fully qualified types: `@Nullable` annotation – must be declared after the last dot (`.`) within inner or fully qualified type names:
- `Cache.@Nullable ValueWrapper` - `Cache.@Nullable ValueWrapper`
- `jakarta.validation.@Nullable Validator` - `jakarta.validation.@Nullable Validator`
@ -153,15 +153,15 @@ parameter cannot be null after a successful invocation of `Assert.notNull()`.
Optionally, it is possible to set `NullAway:JSpecifyMode=true` to enable Optionally, it is possible to set `NullAway:JSpecifyMode=true` to enable
https://github.com/uber/NullAway/wiki/JSpecify-Support[checks on the full JSpecify semantics], including annotations on https://github.com/uber/NullAway/wiki/JSpecify-Support[checks on the full JSpecify semantics], including annotations on
arrays, varargs and generics. Be aware that this mode is arrays, varargs, and generics. Be aware that this mode is
https://github.com/uber/NullAway/issues?q=is%3Aissue+is%3Aopen+label%3Ajspecify[still under development] and requires https://github.com/uber/NullAway/issues?q=is%3Aissue+is%3Aopen+label%3Ajspecify[still under development] and requires
using JDK 22 or later (typically combined with the `--release` Java compiler flag to configure the JDK 22 or later (typically combined with the `--release` Java compiler flag to configure the
expected baseline). It is recommended to enable the JSpecify mode only as a second step, after making sure the codebase expected baseline). It is recommended to enable the JSpecify mode only as a second step, after making sure the codebase
generates no warning with the recommended configuration mentioned previously in this section. generates no warning with the recommended configuration mentioned previously in this section.
==== Warnings suppression ==== Warnings suppression
There are a few valid use cases where NullAway will incorrectly detect nullability problems. In such case, it is recommended There are a few valid use cases where NullAway will incorrectly detect nullability problems. In such cases, it is recommended
to suppress related warnings and to document the reason: 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 - `@SuppressWarnings("NullAway.Init")` at field, constructor, or class level can be used to avoid unnecessary warnings
@ -176,7 +176,7 @@ non-null values even if that cannot be expressed by the API.
- `@SuppressWarnings("NullAway") // Well-known map keys` can be used when `Map#get` invocations are performed with keys that are known - `@SuppressWarnings("NullAway") // Well-known map keys` can be used when `Map#get` invocations are performed with keys that are known
to be present and when non-null related values have been inserted previously. to be present and when non-null related values have been inserted previously.
- `@SuppressWarnings("NullAway") // Overridden method does not define nullability` can be used when the superclass does - `@SuppressWarnings("NullAway") // Overridden method does not define nullability` can be used when the superclass does
not define nullability (typically when the superclass comes from a dependency). not define nullability (typically when the superclass comes from an external dependency).
[[null-safety-migrating]] [[null-safety-migrating]]
@ -194,7 +194,7 @@ and the capability to specify nullability more precisely for more use cases.
A key difference is that Spring's deprecated null-safety annotations, which follow JSR 305 semantics, apply to fields, A key difference is that Spring's deprecated null-safety annotations, which follow JSR 305 semantics, apply to fields,
parameters, and return values; while JSpecify annotations apply to type usage. This subtle difference parameters, and return values; while JSpecify annotations apply to type usage. This subtle difference
is in practice pretty significant, as it allows developers to differentiate between the nullness of elements and the is pretty significant in practice, since it allows developers to differentiate between the nullness of elements and the
nullness of arrays/varargs as well as to define the nullness of generic types. nullness of arrays/varargs as well as to define the nullness of generic types.
That means array and varargs null-safety declarations have to be updated to keep the same semantics. For example That means array and varargs null-safety declarations have to be updated to keep the same semantics. For example
@ -209,6 +209,6 @@ with JSpecify annotations.
`public @Nullable String method()` with JSpecify annotations. `public @Nullable String method()` with JSpecify annotations.
Also, with JSpecify, you do not need to specify `@NonNull` when overriding a type usage annotated with `@Nullable` in the Also, with JSpecify, you do not need to specify `@NonNull` when overriding a type usage annotated with `@Nullable` in the
super method to "undo" the nullable declaration in null-marked code. Just declare it unannotated and the null-marked super method to "undo" the nullable declaration in null-marked code. Just declare it unannotated, and the null-marked
defaults (a type usage is considered non-null unless explicitly annotated as nullable) will apply. defaults will apply (type usage is considered non-null unless explicitly annotated as nullable).

Loading…
Cancel
Save