此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Data Redis 3.4.4! |
存储库方法的 Null 处理
返回单个聚合实例的存储库 CRUD 方法可以使用Optional
以指示可能缺少值。
除此之外, Spring Data 支持在查询方法上返回以下包装器类型:
-
com.google.common.base.Optional
-
scala.Option
-
io.vavr.control.Option
或者,查询方法可以选择根本不使用包装器类型。
然后,通过返回null
.
返回集合、集合替代项、包装器和流的存储库方法保证永远不会返回null
而是相应的空表示。
有关详细信息,请参阅“存储库查询返回类型”。
可为 Null 性注释
JS指定
与在 Spring Framework 7 和 Spring Data 4 上一样,您可以使用 JSpecify 来表达存储库方法的可空性约束。
JSpecify 很好地集成到 IntelliJ 和 Eclipse 中,提供了一种工具友好的方法和可选加入null
检查,如下所示:
-
@NullMarked
:在模块、包和类级别使用,分别声明参数和返回值的默认行为既不是接受也不是生成null
值。 -
@NonNull
:在类型级别用于参数或返回值,这些值不得为null
(不需要的值,其中@NullMarked
适用)。 -
@Nullable
:在类型级别用于参数或返回值,这些值可以是null
. -
@NullUnmarked
:用于包、类和方法级别,以回滚空性声明并从以前的@NullMarked
. 在这种情况下,Nullness 将更改为 unspecified。
@NullMarked
在软件包级别通过package-info.java
文件@NullMarked
package org.springframework.core;
import org.jspecify.annotations.NullMarked;
在属于包的各种 Java 文件中,可为 null 的类型用法是使用@Nullable
.
建议在相关类型之前指定此注释。
例如,对于字段:
private @Nullable String fileEncoding;
或者对于方法参数和返回值:
public static @Nullable String buildMessage(@Nullable String message,
@Nullable Throwable cause) {
// ...
}
重写方法时,不会从超类方法继承 null 注释。 这意味着,如果您只想覆盖实现并保持相同的 API 空性,则应重复这些 null 性注释。
使用数组和 varargs,您需要能够区分元素的 null 性与数组本身的 null 性。 请注意 Java 规范定义的语法,这最初可能会令人惊讶:
-
@Nullable Object[] array
表示单个元素可以为 null,但数组本身不能。 -
Object @Nullable [] array
表示单个元素不能为 null,但数组本身可以。 -
@Nullable Object @Nullable [] array
表示单个元素和数组都可以为 null。
Java 规范还强制要求使用@Target(ElementType.TYPE_USE)
如 JSpecify@Nullable
应在最后一个.
使用内部或完全限定类型:
-
Cache.@Nullable ValueWrapper
-
jakarta.validation.@Nullable Validator
@NonNull
和@NullUnmarked
对于典型用例,应该很少需要。
Spring 框架可空性和 JSR-305 注释
您可以使用 Spring Framework 的可为 null 性注释来表达存储库方法的可为 null 性约束。
与 Spring Framework 7 一样,Spring 的可空性 Comments 已被弃用,取而代之的是 JSpecify。 有关更多信息,请参阅有关从 Spring 空安全注释迁移到 JSpecify 的框架文档。 |
它们提供了一种工具友好的方法和选择加入null
检查,如下所示:
-
@NonNullApi
:在包级别用于声明参数和返回值的默认行为分别是既不接受也不生成null
值。 -
@NonNull
:用于不得为null
(在参数和返回值上不需要,其中@NonNullApi
适用)。 -
@Nullable
:用于参数或返回值,该参数或返回值可以是null
.
Spring 注解使用 JSR 305 注解(一种休眠但广泛使用的 JSR)进行元注解。
JSR 305 元注释允许工具供应商(例如 IDEA、Eclipse 和 Kotlin)以通用方式提供空安全支持,而不必对 Spring 注释进行硬编码支持。
要启用查询方法的可为 null 性约束的运行时检查,您需要使用 Spring 的@NonNullApi
在package-info.java
,如以下示例所示:
package-info.java
@org.springframework.lang.NonNullApi
package com.acme;
一旦非 null 默认值到位,存储库查询方法调用将在运行时验证是否为 null 性约束。
如果查询结果违反定义的约束,则会引发异常。
当方法返回null
但被声明为不可为空(在存储库所在的包上定义的注释的默认值)。
如果您想再次选择加入可为 null 的结果,请有选择地使用@Nullable
在单个方法上。
使用本节开头提到的结果包装器类型将继续按预期工作:空结果将转换为表示 absence 的值。
以下示例显示了刚才描述的许多技术:
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
.
Nullability in Kotlin-based Repositories
Kotlin has the definition of 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
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.