|  | 
| 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 | 
| 5 |  | -provides the following annotations in the `org.springframework.lang` package to let you | 
| 6 |  | -declare nullability of APIs and fields: | 
|  | 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 nullability 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. | 
| 7 | 8 | 
 | 
| 8 |  | -* {spring-framework-api}/lang/Nullable.html[`@Nullable`]: Annotation to indicate that a | 
| 9 |  | -specific parameter, return value, or field can be `null`. | 
| 10 |  | -* {spring-framework-api}/lang/NonNull.html[`@NonNull`]: Annotation to indicate that a specific | 
| 11 |  | -parameter, return value, or field cannot be `null` (not needed on parameters, return values, | 
| 12 |  | -and fields where `@NonNullApi` and `@NonNullFields` apply, respectively). | 
| 13 |  | -* {spring-framework-api}/lang/NonNullApi.html[`@NonNullApi`]: Annotation at the package level | 
| 14 |  | -that declares non-null as the default semantics for parameters and return values. | 
| 15 |  | -* {spring-framework-api}/lang/NonNullFields.html[`@NonNullFields`]: Annotation at the package | 
| 16 |  | -level that declares non-null as the default semantics for fields. | 
|  | 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 nullability 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 | 
|  | 13 | +{kotlin-docs}/null-safety.html[Kotlin's null safety]. | 
| 17 | 14 | 
 | 
| 18 |  | -The Spring Framework itself leverages these annotations, but they can also be used in any | 
| 19 |  | -Spring-based Java project to declare null-safe APIs and optionally null-safe fields. | 
| 20 |  | -Nullability declarations for generic type arguments, varargs, and array elements are not supported yet. | 
| 21 |  | -Nullability declarations are expected to be fine-tuned between Spring Framework releases, | 
| 22 |  | -including minor ones. Nullability of types used inside method bodies is outside the | 
| 23 |  | -scope of this feature. | 
|  | 15 | +`@Nullable` annotations are also used at runtime to infer if a parameter is optional or not, for example via | 
|  | 16 | +{spring-framework-api}/core/MethodParameter.html#isOptional()[`MethodParameter#isOptional`]. | 
| 24 | 17 | 
 | 
| 25 |  | -NOTE: Other common libraries such as Reactor and Spring Data provide null-safe APIs that | 
| 26 |  | -use a similar nullability arrangement, delivering a consistent overall experience for | 
| 27 |  | -Spring application developers. | 
|  | 18 | +[[null-safety-libraries]] | 
|  | 19 | +== Annotating libraries with JSpecify annotations | 
| 28 | 20 | 
 | 
|  | 21 | +As of Spring Framework 7, the Spring Framework codebase leverages JSpecify annotations to expose null-safe APIs and | 
|  | 22 | +to check the consistency of those null-safety declarations with https://github.com/uber/NullAway[NullAway] as part of | 
|  | 23 | +its build. It is recommended for each library depending on Spring Framework (Spring portfolio projects), as | 
|  | 24 | +well as other libraries related to the Spring ecosystem (Reactor, Micrometer and Spring community projects), to do the | 
|  | 25 | +same. | 
| 29 | 26 | 
 | 
|  | 27 | +[[null-safety-applications]] | 
|  | 28 | +== Leveraging JSpecify annotations in Spring applications | 
| 30 | 29 | 
 | 
|  | 30 | +Developing applications with IDEs supporting null-safety annotations, such as IntelliJ IDEA or Eclipse, will provide | 
|  | 31 | +warnings in Java and errors in Kotlin when the null-safety contracts are not honored, allowing Spring application | 
|  | 32 | +developers to refine their null handling to prevent `NullPointerException` to be thrown at runtime. | 
| 31 | 33 | 
 | 
| 32 |  | -[[use-cases]] | 
| 33 |  | -== Use cases | 
|  | 34 | +Optionally, Spring application developers can annotate their codebase and use https://github.com/uber/NullAway[NullAway] | 
|  | 35 | +to enforce null-safety during build time at application level. | 
| 34 | 36 | 
 | 
| 35 |  | -In addition to providing an explicit declaration for Spring Framework API nullability, | 
| 36 |  | -these annotations can be used by an IDE (such as IDEA or Eclipse) to provide useful | 
| 37 |  | -warnings related to null-safety in order to avoid `NullPointerException` at runtime. | 
|  | 37 | +[[null-safety-guidelines]] | 
|  | 38 | +== Guidelines | 
| 38 | 39 | 
 | 
| 39 |  | -They are also used to make Spring APIs null-safe in Kotlin projects, since Kotlin natively | 
| 40 |  | -supports {kotlin-docs}/null-safety.html[null-safety]. More details | 
| 41 |  | -are available in the xref:languages/kotlin/null-safety.adoc[Kotlin support documentation]. | 
|  | 40 | +The purpose of this section is to share some guidelines proposed for using JSpecify annotations in the context of | 
|  | 41 | +Spring-related libraries or applications. | 
| 42 | 42 | 
 | 
|  | 43 | +The key points to understand is that by default, the nullability of types is unknown in Java, and that non-null type | 
|  | 44 | +usages are by far more frequent than nullable ones. In order to keep codebases readable, we typically want to define | 
|  | 45 | +that by default, type usages are non-null unless marked as nullable for a specific scope. This is exactly the purpose of | 
|  | 46 | +https://jspecify.dev/docs/api/org/jspecify/annotations/NullMarked.html[`@NullMarked`] that is typically set with Spring | 
|  | 47 | +at package level via a `package-info.java` file, for example: | 
| 43 | 48 | 
 | 
|  | 49 | +[source,java,subs="verbatim,quotes",chomp="-packages",fold="none"] | 
|  | 50 | +---- | 
|  | 51 | +@NullMarked | 
|  | 52 | +package org.springframework.core; | 
| 44 | 53 | 
 | 
|  | 54 | +import org.jspecify.annotations.NullMarked; | 
|  | 55 | +---- | 
| 45 | 56 | 
 | 
| 46 |  | -[[jsr-305-meta-annotations]] | 
| 47 |  | -== JSR-305 meta-annotations | 
|  | 57 | +In the various Java files belonging to the package, nullable type usages are defined explicitly with | 
|  | 58 | +https://jspecify.dev/docs/api/org/jspecify/annotations/Nullable.html[`@Nullable`]. It is recommended that this | 
|  | 59 | +annotation is specified just before the related type. | 
| 48 | 60 | 
 | 
| 49 |  | -Spring annotations are meta-annotated with {JSR}305[JSR 305] | 
| 50 |  | -annotations (a dormant but widespread JSR). JSR-305 meta-annotations let tooling vendors | 
| 51 |  | -like IDEA or Kotlin provide null-safety support in a generic way, without having to | 
| 52 |  | -hard-code support for Spring annotations. | 
|  | 61 | +For example, for a field: | 
|  | 62 | + | 
|  | 63 | +[source,java,subs="verbatim,quotes"] | 
|  | 64 | +---- | 
|  | 65 | +private @Nullable String fileEncoding; | 
|  | 66 | +---- | 
|  | 67 | + | 
|  | 68 | +Or for method parameters and return value: | 
|  | 69 | + | 
|  | 70 | +[source,java,subs="verbatim,quotes"] | 
|  | 71 | +---- | 
|  | 72 | +public static @Nullable String buildMessage(@Nullable String message, | 
|  | 73 | +                                            @Nullable Throwable cause) { | 
|  | 74 | +    // ... | 
|  | 75 | +} | 
|  | 76 | +---- | 
|  | 77 | + | 
|  | 78 | +When overriding a method, nullability annotations are not inherited from the superclass method. That means those | 
|  | 79 | +nullability annotations should be repeated if you just want to override the implementation and keep the same API | 
|  | 80 | +nullability. | 
|  | 81 | + | 
|  | 82 | +With arrays and varargs, you need to be able to differentiate the nullability of the elements from the nullability of | 
|  | 83 | +the array itself. Pay attention to the syntax | 
|  | 84 | +https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.4[defined by the Java specification] which may be | 
|  | 85 | +initially surprising: | 
|  | 86 | + | 
|  | 87 | +- `@Nullable Object[] array` means individual elements can be null but the array itself can't. | 
|  | 88 | +- `Object @Nullable [] array` means individual elements can't be null but the array itself can. | 
|  | 89 | +- `@Nullable Object @Nullable [] array` means both individual elements and the array can be null. | 
|  | 90 | + | 
|  | 91 | +The Java specifications also enforces that annotations defined with `@Target(ElementType.TYPE_USE)` like JSpecify | 
|  | 92 | +`@Nullable` should be specified after the last `.` with inner or fully qualified types: | 
|  | 93 | + | 
|  | 94 | + - `Cache.@Nullable ValueWrapper` | 
|  | 95 | + - `jakarta.validation.@Nullable Validator` | 
|  | 96 | + | 
|  | 97 | +https://jspecify.dev/docs/api/org/jspecify/annotations/NonNull.html[`@NonNull`] and | 
|  | 98 | +https://jspecify.dev/docs/api/org/jspecify/annotations/NullUnmarked.html[`@NullUnmarked`] should rarely be needed for | 
|  | 99 | +typical use cases. | 
|  | 100 | + | 
|  | 101 | +The {spring-framework-api}/lang/Contract.html[@Contract] annotation in the `org.springframework.lang` package | 
|  | 102 | +can be used to express complementary semantics to avoid non-relevant null-safety warnings in your codebase. | 
|  | 103 | + | 
|  | 104 | +NOTE: Complementary to nullability annotations, the {spring-framework-api}/lang/CheckReturnValue.html[@CheckReturnValue] | 
|  | 105 | +annotation in the `org.springframework.lang` package can be used to specify that the method return value must be used. | 
|  | 106 | + | 
|  | 107 | +[[null-safety-migrating]] | 
|  | 108 | +== Migrating from Spring null-safety annotations | 
|  | 109 | + | 
|  | 110 | +Spring null-safety annotations {spring-framework-api}/lang/Nullable.html[`@Nullable`], | 
|  | 111 | +{spring-framework-api}/lang/NonNull.html[`@NonNull`], | 
|  | 112 | +{spring-framework-api}/lang/NonNullApi.html[`@NonNullApi`], and | 
|  | 113 | +{spring-framework-api}/lang/NonNullFields.html[`@NonNullFields`] in the `org.springframework.lang` package are | 
|  | 114 | +deprecated as of Spring Framework 7 and superseded by JSpecify annotations. | 
|  | 115 | + | 
|  | 116 | +A key difference is that Spring null-safety annotations, following JSR 305 semantics, apply to fields, | 
|  | 117 | +parameters and return values while JSpecify annotations apply to type usages. This subtle difference | 
|  | 118 | +is in practice pretty significant, as it allows for example to differentiate the nullability of elements from the | 
|  | 119 | +nullability of arrays/varargs as well as defining the nullability of generic types. | 
|  | 120 | + | 
|  | 121 | +That means array and varargs null-safety declarations have to be updated to keep the same semantic. For example | 
|  | 122 | +`@Nullable Object[] array` with Spring annotations needs to be changed to `Object @Nullable [] array` with JSpecify | 
|  | 123 | +annotations. Same for varargs. | 
|  | 124 | + | 
|  | 125 | +It is also recommended to move field and return value annotations closer to the type, for example: | 
|  | 126 | + | 
|  | 127 | + - For fields, instead of `@Nullable private String field` with Spring annotations, use `private @Nullable String field` | 
|  | 128 | +with JSpecify annotations. | 
|  | 129 | +- For return values, instead of `@Nullable public String method()` with Spring annotations, use | 
|  | 130 | +`public @Nullable String method()` with JSpecify annotations. | 
|  | 131 | + | 
|  | 132 | +Also, with JSpecify, you don't need to specify `@NonNull` when overriding a type usage annotated with `@Nullable` in the | 
|  | 133 | +super method to "undo" the nullable declaration in null-marked code. Just declare it unannotated and the null-marked | 
|  | 134 | +defaults (a type usage is considered non-null unless explicitly annotated as nullable) will apply. | 
| 53 | 135 | 
 | 
| 54 |  | -It is neither necessary nor recommended to add a JSR-305 dependency to the project classpath to | 
| 55 |  | -take advantage of Spring's null-safe APIs. Only projects such as Spring-based libraries that use | 
| 56 |  | -null-safety annotations in their codebase should add `com.google.code.findbugs:jsr305:3.0.2` | 
| 57 |  | -with `compileOnly` Gradle configuration or Maven `provided` scope to avoid compiler warnings. | 
|  | 
0 commit comments