此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Data Commons 3.4.5! |
存储库方法的 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
:用于模块、包和类级别,分别声明参数和返回值的默认行为既不是 accept 也不是 producenull
值。 -
@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
一旦非 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 | 存储库驻留在我们为其定义了非 null 行为的包(或子包)中。 |
2 | 抛出一个EmptyResultDataAccessException 当查询未产生结果时。
抛出一个IllegalArgumentException 当emailAddress 传递给 method 是null . |
3 | 返回null 当查询未产生结果时。
也接受null 作为emailAddress . |
4 | 返回Optional.empty() 当查询未产生结果时。
抛出一个IllegalArgumentException 当emailAddress 传递给 method 是null . |
基于 Kotlin 的存储库中的 Null 性
Kotlin 将可为 null 性约束的定义融入到语言中。
Kotlin 代码编译为字节码,字节码不通过方法签名来表示可为 null 性约束,而是通过编译的元数据来表示。
确保包含kotlin-reflect
JAR 来启用对 Kotlin 的可为 null 性约束的自省。
Spring Data 存储库使用语言机制来定义这些约束以应用相同的运行时检查,如下所示:
interface UserRepository : Repository<User, String> {
fun findByUsername(username: String): User (1)
fun findByFirstname(firstname: String?): User? (2)
}
1 | 该方法将参数和结果定义为不可为 null(Kotlin 默认值)。
Kotlin 编译器会拒绝传递null 添加到方法中。
如果查询产生空结果,则EmptyResultDataAccessException 被抛出。 |
2 | 此方法接受null 对于firstname parameter 并返回null 如果查询未产生结果。 |