Revisit nullability annotations

This commit introduces the following changes.

1) It adds a new Spring @NonNull annotation which allows to apply
@NonNullApi semantic on a specific element, like @Nullable does.
Combined with @Nullable, it allows partial null-safety support when
package granularity is too broad.

2) @Nullable and @NonNull can apply to ElementType.TYPE_USE in order
to be used on generic type arguments (SPR-15942).

3) Annotations does not apply to ElementType.TYPE_PARAMETER anymore
since it is not supported yet (applicability for such use case is
controversial and need to be discussed).

4) @NonNullApi does not apply to ElementType.FIELD anymore since in a
lot of use cases (private, protected) it is not part for the public API
+ its usage should remain opt-in. A dedicated @NonNullFields annotation
has been added in order to set fields default to non-nullable.

5) Updated Javadoc and reference documentation.

Issue: SPR-15756
This commit is contained in:
Sebastien Deleuze
2017-09-15 13:26:41 +02:00
parent ec2218c967
commit 1bc93e3d0f
364 changed files with 1003 additions and 113 deletions

View File

@@ -31,3 +31,5 @@ include::core/core-aop.adoc[leveloffset=+1]
include::core/core-aop-api.adoc[leveloffset=+1]
include::core/core-null-safety.adoc[leveloffset=+1]

View File

@@ -0,0 +1,53 @@
[[null-safety]]
= Null-safety
Although Java does not allow to express null-safety with its type system, Spring Framework
now provides annotations declared in the `org.springframework.lang` package to declare
nullability of APIs and fields.
Spring Framework leverages these annotations, but they can also be used in any Spring based
Java project to declare null-safe APIs and optionally null-safe fields. Nullability of
types used inside method bodies is outside of the scope of this feature.
These annotations are meta-annotated with https://jcp.org/en/jsr/detail?id=305[JSR 305]
annotations (a dormant JSR but supported by tools like IntelliJ IDEA) to provide useful
warnings to Java developers related to null-safety in order to avoid `NullPointerException`
at runtime. JSR 305 meta-annotations allows tooling vendors to provide null-safety support
in a generic way, without having to hard-code support for Spring annotations.
They are also used by Kotlin which supports natively
https://kotlinlang.org/docs/reference/null-safety.html[null-safety]. By default, types from
Java APIs used in Kotlin are recognized as
https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[platform types]
for which null-checks are relaxed.
https://github.com/Kotlin/KEEP/blob/jsr-305/proposals/jsr-305-custom-nullability-qualifiers.md[Kotlin support for JSR 305 annotations]
+ Spring nullability annotations provide null-safety for the whole Spring Framework API to Kotlin developers,
with the advantage of dealing with `null` related issues at compile time rather than bumping into the famous
`NullPointerException` at runtime. More details are available in <<kotlin#null-safety,Kotlin support documentation>>.
[NOTE]
====
Other libraries like Reactor or Spring Data leverage these annotations as well to provide
null-safe APIs.
====
The following annotations are provided:
* {api-spring-framework}/lang/NonNull.html[`@NonNull`] annotation where specific parameter,
return value, generic type argument, varargs element, array element or field cannot be `null`
(not needed on parameter and return value where `@NonNullApi` and `@NonNullFields` applies) .
* {api-spring-framework}/lang/Nullable.html[`@Nullable`] annotation where specific
parameter, return value, generic type argument, varargs element, array element or field
can be `null`.
* {api-spring-framework}/lang/NonNullApi.html[`@NonNullApi`] annotation at package level
declares non-null as the default behavior for parameters and return values.
* {api-spring-framework}/lang/NonNullFields.html[`@NonNullFields`] annotation at package
level declares non-null as the default behavior for fields.
[NOTE]
====
Generic type arguments, varargs and array elements are out of the scope of `@NonNullApi`
and `@NonNullFields`, because `@TypeQualifierDefault(ElementType.TYPE_USE)` would apply to
a lot of other use cases. As a consequence, nullability for such elements need to be specified
explicitly with `@NonNull` and `@Nullable`.
====

View File

@@ -5,6 +5,7 @@
:toc: left
:toclevels: 2
[[introduction]]
== Introduction
https://kotlinlang.org[Kotlin] is a statically-typed language targeting the JVM (and other platforms)
@@ -15,6 +16,7 @@ existing libraries written in Java.
Spring Framework 5 introduces first-class support for Kotlin and allows developers to write
Spring + Kotlin applications almost as if the Spring Framework was a native Kotlin framework.
[[requirements]]
== Requirements ==
Spring Framework supports Kotlin 1.1+ and requires
@@ -25,6 +27,7 @@ and https://bintray.com/bintray/jcenter/org.jetbrains.kotlin%3Akotlin-reflect[`k
to be present on the classpath. They are provided by default if one bootstraps a Kotlin project on
https://start.spring.io/#!language=kotlin[start.spring.io].
[[extensions]]
== Extensions
Thanks to its great https://kotlinlang.org/docs/reference/java-interop.html[Java interoperability]
@@ -74,6 +77,7 @@ val users : Flux<User> = client.get().retrieve().bodyToFlux()
As in Java, `users` in Kotlin is strongly typed, but Kotlin's clever type inference allows
for a shorter syntax.
[[null-safety]]
== Null-safety
One of Kotlin's key features is https://kotlinlang.org/docs/reference/null-safety.html[null-safety]
@@ -84,21 +88,15 @@ declarations and expressing "value or no value" semantics without paying the cos
http://www.baeldung.com/kotlin-null-safety[comprehensive guide to Kotlin null-safety].)
Although Java does not allow one to express null-safety in its type-system, Spring Framework now
provides https://jira.spring.io/browse/SPR-15540[null-safety of the whole Spring Framework API]
via tooling-friendly annotations:
* `@NonNullApi` annotations at package level declare non-null as the default behavior
* `@Nullable` annotations where specific parameters or return values can be `null`.
Both annotations are meta-annotated with https://jcp.org/en/jsr/detail?id=305[JSR 305]
annotations (a dormant JSR but supported by tools like IDEA, Findbugs, etc.)
to provide useful warnings to Java developers.
On the Kotlin side - as of https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-1-4-is-out/[Kotlin 1.1.4 release] -
these annotations https://github.com/Kotlin/KEEP/blob/jsr-305/proposals/jsr-305-custom-nullability-qualifiers.md[are recognized by Kotlin]
in order to provide null-safety for the whole Spring Framework API. That means
one should never experience a `NullPointerException` when using Spring Framework and Kotlin because
the compiler will not allow it.
provides <<core#null-safety,null-safety of the whole Spring Framework API>>
via tooling-friendly annotations declared in the `org.springframework.lang` package.
By default, types from Java APIs used in Kotlin are recognized as
https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[platform types]
for which null-checks are relaxed.
https://github.com/Kotlin/KEEP/blob/jsr-305/proposals/jsr-305-custom-nullability-qualifiers.md[Kotlin support for JSR 305 annotations]
available as of https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-1-4-is-out/[1.1.4 release]
+ Spring nullability annotations provide null-safety for the whole Spring Framework API to Kotlin developers,
with the advantage of dealing with `null` related issues at compile time.
For now, one needs to use a `-Xjsr305-annotations=enable` flag (specified via the
`freeCompilerArgs` property with Maven or Gradle Kotlin plugins), but that should become
@@ -109,10 +107,11 @@ until Kotlin 1.1.5 is released (it will fix https://youtrack.jetbrains.com/issue
[NOTE]
====
Other libraries like Reactor and Spring Data leverage these annotations to provide
Other libraries like Reactor and Spring Data leverage these annotations as well to provide
null-safe APIs for Kotlin developers.
====
[[classes-interfaces]]
== Classes & Interfaces
Spring Framework supports various Kotlin constructs like instantiating Kotlin classes
@@ -133,6 +132,7 @@ detected without the Jackson Kotlin module present.
As of Spring Boot 2.0, Jackson Kotlin module is automatically provided via the JSON starter.
====
[[annotations]]
== Annotations
Spring Framework also takes advantage of https://kotlinlang.org/docs/reference/null-safety.html[Kotlin null-safety]
@@ -146,6 +146,7 @@ to determine if a bean is required or not. `@Autowired lateinit var foo: Foo` im
of type `Foo` must be registered in the application context while `@Autowired lateinit var foo: Foo?`
wont raise an error if such bean does not exist.
[[bean-definition-dsl]]
== Bean definition DSL
Spring Framework 5 introduces a new way to register beans in a functional way using lambdas
@@ -247,6 +248,7 @@ see https://stackoverflow.com/questions/45935931/how-to-use-functional-bean-defi
for more details and up-to-date information.
====
[[web]]
== Web
=== WebFlux Functional DSL
@@ -321,6 +323,7 @@ ${include("footer")}
See https://github.com/sdeleuze/kotlin-script-templating[kotlin-script-templating] example
project for more details.
[[spring-projects-in-kotlin]]
== Spring projects in Kotlin
This section provides a focus on some specific hints and recommendations worth
@@ -532,6 +535,7 @@ class IntegrationTests {
}
----
[[getting-started]]
== Getting started
=== start.spring.io
@@ -554,6 +558,7 @@ Kotlin DSL.
For other use cases, Spring MVC and its annotation-based programming model is a perfectly
valid and fully supported choice.
[[resources-started]]
== Resources
* http://kotlinlang.org/docs/reference/[Kotlin language reference]