Polishing.
Reorder null-handling and collection return types in documentation to improve topical flow. See #2804
This commit is contained in:
97
src/main/asciidoc/repositories-null-handling.adoc
Normal file
97
src/main/asciidoc/repositories-null-handling.adoc
Normal file
@@ -0,0 +1,97 @@
|
||||
[[repositories.nullability]]
|
||||
=== Null Handling of Repository Methods
|
||||
|
||||
As of Spring Data 2.0, repository CRUD methods that return an individual aggregate instance use Java 8's `Optional` to indicate the potential absence of a value.
|
||||
Besides that, Spring Data supports returning the following wrapper types on query methods:
|
||||
|
||||
* `com.google.common.base.Optional`
|
||||
* `scala.Option`
|
||||
* `io.vavr.control.Option`
|
||||
|
||||
Alternatively, query methods can choose not to use a wrapper type at all.
|
||||
The absence of a query result is then indicated by returning `null`.
|
||||
Repository methods returning collections, collection alternatives, wrappers, and streams are guaranteed never to return `null` but rather the corresponding empty representation.
|
||||
See "`<<repository-query-return-types>>`" for details.
|
||||
|
||||
[[repositories.nullability.annotations]]
|
||||
==== Nullability Annotations
|
||||
|
||||
You can express nullability constraints for repository methods by using {spring-framework-docs}/core.html#null-safety[Spring Framework's nullability annotations].
|
||||
They provide a tooling-friendly approach and opt-in `null` checks during runtime, as follows:
|
||||
|
||||
* {spring-framework-javadoc}/org/springframework/lang/NonNullApi.html[`@NonNullApi`]: Used on the package level to declare that the default behavior for parameters and return values is, respectively, neither to accept nor to produce `null` values.
|
||||
* {spring-framework-javadoc}/org/springframework/lang/NonNull.html[`@NonNull`]: Used on a parameter or return value that must not be `null` (not needed on a parameter and return value where `@NonNullApi` applies).
|
||||
* {spring-framework-javadoc}/org/springframework/lang/Nullable.html[`@Nullable`]: Used on a parameter or return value that can be `null`.
|
||||
|
||||
Spring annotations are meta-annotated with https://jcp.org/en/jsr/detail?id=305[JSR 305] annotations (a dormant but widely used JSR).
|
||||
JSR 305 meta-annotations let tooling vendors (such as https://www.jetbrains.com/help/idea/nullable-and-notnull-annotations.html[IDEA], https://help.eclipse.org/latest/index.jsp?topic=/org.eclipse.jdt.doc.user/tasks/task-using_external_null_annotations.htm[Eclipse], and link:https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[Kotlin]) provide null-safety support in a generic way, without having to hard-code support for Spring annotations.
|
||||
To enable runtime checking of nullability constraints for query methods, you need to activate non-nullability on the package level by using Spring’s `@NonNullApi` in `package-info.java`, as shown in the following example:
|
||||
|
||||
.Declaring Non-nullability in `package-info.java`
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@org.springframework.lang.NonNullApi
|
||||
package com.acme;
|
||||
----
|
||||
====
|
||||
|
||||
Once non-null defaulting is in place, repository query method invocations get validated at runtime for nullability constraints.
|
||||
If a query result violates the defined constraint, an exception is thrown.
|
||||
This happens when the method would return `null` but is declared as non-nullable (the default with the annotation defined on the package in which the repository resides).
|
||||
If you want to opt-in to nullable results again, selectively use `@Nullable` on individual methods.
|
||||
Using the result wrapper types mentioned at the start of this section continues to work as expected: an empty result is translated into the value that represents absence.
|
||||
|
||||
The following example shows a number of the techniques just described:
|
||||
|
||||
.Using different nullability constraints
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
package com.acme; <1>
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
interface UserRepository extends Repository<User, Long> {
|
||||
|
||||
User getByEmailAddress(EmailAddress emailAddress); <2>
|
||||
|
||||
@Nullable
|
||||
User findByEmailAddress(@Nullable EmailAddress emailAdress); <3>
|
||||
|
||||
Optional<User> findOptionalByEmailAddress(EmailAddress emailAddress); <4>
|
||||
}
|
||||
----
|
||||
<1> The repository resides in a package (or sub-package) for which we have defined non-null behavior.
|
||||
<2> Throws an `EmptyResultDataAccessException` when the query does not produce a result.
|
||||
Throws an `IllegalArgumentException` when the `emailAddress` handed to the method is `null`.
|
||||
<3> Returns `null` when the query does not produce a result.
|
||||
Also accepts `null` as the value for `emailAddress`.
|
||||
<4> Returns `Optional.empty()` when the query does not produce a result.
|
||||
Throws an `IllegalArgumentException` when the `emailAddress` handed to the method is `null`.
|
||||
====
|
||||
|
||||
[[repositories.nullability.kotlin]]
|
||||
==== Nullability in Kotlin-based Repositories
|
||||
|
||||
Kotlin has the definition of https://kotlinlang.org/docs/reference/null-safety.html[nullability constraints] baked into the language.
|
||||
Kotlin code compiles to bytecode, which does not express nullability constraints through method signatures but rather through compiled-in metadata.
|
||||
Make sure to include the `kotlin-reflect` JAR in your project to enable introspection of Kotlin's nullability constraints.
|
||||
Spring Data repositories use the language mechanism to define those constraints to apply the same runtime checks, as follows:
|
||||
|
||||
.Using nullability constraints on Kotlin repositories
|
||||
====
|
||||
[source,kotlin]
|
||||
----
|
||||
interface UserRepository : Repository<User, String> {
|
||||
|
||||
fun findByUsername(username: String): User <1>
|
||||
|
||||
fun findByFirstname(firstname: String?): User? <2>
|
||||
}
|
||||
----
|
||||
<1> The method defines both the parameter and the result as non-nullable (the Kotlin default).
|
||||
The Kotlin compiler rejects method invocations that pass `null` to the method.
|
||||
If the query yields an empty result, an `EmptyResultDataAccessException` is thrown.
|
||||
<2> This method accepts `null` for the `firstname` parameter and returns `null` if the query does not produce a result.
|
||||
====
|
||||
@@ -57,7 +57,6 @@ Rather, it restricts the query to look up only the given range of entities.
|
||||
NOTE: To find out how many pages you get for an entire query, you have to trigger an additional count query.
|
||||
By default, this query is derived from the query you actually trigger.
|
||||
|
||||
|
||||
[[repositories.scrolling.guidance]]
|
||||
==== Which Method is Appropriate?
|
||||
|
||||
@@ -178,7 +177,6 @@ ifdef::feature-scroll[]
|
||||
include::repositories-scrolling.adoc[]
|
||||
endif::[]
|
||||
|
||||
|
||||
[[repositories.limit-query-result]]
|
||||
=== Limiting Query Results
|
||||
|
||||
|
||||
@@ -619,103 +619,6 @@ You can use the types in the first column (or subtypes thereof) as query method
|
||||
Alternatively, you can declare `Traversable` (the Vavr `Iterable` equivalent), and we then derive the implementation class from the actual return value.
|
||||
That is, a `java.util.List` is turned into a Vavr `List` or `Seq`, a `java.util.Set` becomes a Vavr `LinkedHashSet` `Set`, and so on.
|
||||
|
||||
[[repositories.nullability]]
|
||||
=== Null Handling of Repository Methods
|
||||
|
||||
As of Spring Data 2.0, repository CRUD methods that return an individual aggregate instance use Java 8's `Optional` to indicate the potential absence of a value.
|
||||
Besides that, Spring Data supports returning the following wrapper types on query methods:
|
||||
|
||||
* `com.google.common.base.Optional`
|
||||
* `scala.Option`
|
||||
* `io.vavr.control.Option`
|
||||
|
||||
Alternatively, query methods can choose not to use a wrapper type at all.
|
||||
The absence of a query result is then indicated by returning `null`.
|
||||
Repository methods returning collections, collection alternatives, wrappers, and streams are guaranteed never to return `null` but rather the corresponding empty representation.
|
||||
See "`<<repository-query-return-types>>`" for details.
|
||||
|
||||
[[repositories.nullability.annotations]]
|
||||
==== Nullability Annotations
|
||||
|
||||
You can express nullability constraints for repository methods by using {spring-framework-docs}/core.html#null-safety[Spring Framework's nullability annotations].
|
||||
They provide a tooling-friendly approach and opt-in `null` checks during runtime, as follows:
|
||||
|
||||
* {spring-framework-javadoc}/org/springframework/lang/NonNullApi.html[`@NonNullApi`]: Used on the package level to declare that the default behavior for parameters and return values is, respectively, neither to accept nor to produce `null` values.
|
||||
* {spring-framework-javadoc}/org/springframework/lang/NonNull.html[`@NonNull`]: Used on a parameter or return value that must not be `null` (not needed on a parameter and return value where `@NonNullApi` applies).
|
||||
* {spring-framework-javadoc}/org/springframework/lang/Nullable.html[`@Nullable`]: Used on a parameter or return value that can be `null`.
|
||||
|
||||
Spring annotations are meta-annotated with https://jcp.org/en/jsr/detail?id=305[JSR 305] annotations (a dormant but widely used JSR).
|
||||
JSR 305 meta-annotations let tooling vendors (such as https://www.jetbrains.com/help/idea/nullable-and-notnull-annotations.html[IDEA], https://help.eclipse.org/latest/index.jsp?topic=/org.eclipse.jdt.doc.user/tasks/task-using_external_null_annotations.htm[Eclipse], and link:https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types[Kotlin]) provide null-safety support in a generic way, without having to hard-code support for Spring annotations.
|
||||
To enable runtime checking of nullability constraints for query methods, you need to activate non-nullability on the package level by using Spring’s `@NonNullApi` in `package-info.java`, as shown in the following example:
|
||||
|
||||
.Declaring Non-nullability in `package-info.java`
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@org.springframework.lang.NonNullApi
|
||||
package com.acme;
|
||||
----
|
||||
====
|
||||
|
||||
Once non-null defaulting is in place, repository query method invocations get validated at runtime for nullability constraints.
|
||||
If a query result violates the defined constraint, an exception is thrown.
|
||||
This happens when the method would return `null` but is declared as non-nullable (the default with the annotation defined on the package in which the repository resides).
|
||||
If you want to opt-in to nullable results again, selectively use `@Nullable` on individual methods.
|
||||
Using the result wrapper types mentioned at the start of this section continues to work as expected: an empty result is translated into the value that represents absence.
|
||||
|
||||
The following example shows a number of the techniques just described:
|
||||
|
||||
.Using different nullability constraints
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
package com.acme; <1>
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
interface UserRepository extends Repository<User, Long> {
|
||||
|
||||
User getByEmailAddress(EmailAddress emailAddress); <2>
|
||||
|
||||
@Nullable
|
||||
User findByEmailAddress(@Nullable EmailAddress emailAdress); <3>
|
||||
|
||||
Optional<User> findOptionalByEmailAddress(EmailAddress emailAddress); <4>
|
||||
}
|
||||
----
|
||||
<1> The repository resides in a package (or sub-package) for which we have defined non-null behavior.
|
||||
<2> Throws an `EmptyResultDataAccessException` when the query does not produce a result.
|
||||
Throws an `IllegalArgumentException` when the `emailAddress` handed to the method is `null`.
|
||||
<3> Returns `null` when the query does not produce a result.
|
||||
Also accepts `null` as the value for `emailAddress`.
|
||||
<4> Returns `Optional.empty()` when the query does not produce a result.
|
||||
Throws an `IllegalArgumentException` when the `emailAddress` handed to the method is `null`.
|
||||
====
|
||||
|
||||
[[repositories.nullability.kotlin]]
|
||||
==== Nullability in Kotlin-based Repositories
|
||||
|
||||
Kotlin has the definition of https://kotlinlang.org/docs/reference/null-safety.html[nullability constraints] baked into the language.
|
||||
Kotlin code compiles to bytecode, which does not express nullability constraints through method signatures but rather through compiled-in metadata.
|
||||
Make sure to include the `kotlin-reflect` JAR in your project to enable introspection of Kotlin's nullability constraints.
|
||||
Spring Data repositories use the language mechanism to define those constraints to apply the same runtime checks, as follows:
|
||||
|
||||
.Using nullability constraints on Kotlin repositories
|
||||
====
|
||||
[source,kotlin]
|
||||
----
|
||||
interface UserRepository : Repository<User, String> {
|
||||
|
||||
fun findByUsername(username: String): User <1>
|
||||
|
||||
fun findByFirstname(firstname: String?): User? <2>
|
||||
}
|
||||
----
|
||||
<1> The method defines both the parameter and the result as non-nullable (the Kotlin default).
|
||||
The Kotlin compiler rejects method invocations that pass `null` to the method.
|
||||
If the query yields an empty result, an `EmptyResultDataAccessException` is thrown.
|
||||
<2> This method accepts `null` for the `firstname` parameter and returns `null` if the query does not produce a result.
|
||||
====
|
||||
|
||||
[[repositories.query-streaming]]
|
||||
=== Streaming Query Results
|
||||
@@ -752,6 +655,8 @@ try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
|
||||
|
||||
NOTE: Not all Spring Data modules currently support `Stream<T>` as a return type.
|
||||
|
||||
include::repositories-null-handling.adoc[]
|
||||
|
||||
[[repositories.query-async]]
|
||||
=== Asynchronous Query Results
|
||||
|
||||
|
||||
Reference in New Issue
Block a user