此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Data Commons 3.5.3spring-doc.cadn.net.cn

存储库方法的 Null 处理

返回单个聚合实例的存储库 CRUD 方法可以使用Optional以指示可能缺少值。 除此之外,Spring Data 支持在查询方法上返回以下包装器类型:spring-doc.cadn.net.cn

或者,查询方法可以选择根本不使用包装器类型。 然后,通过返回null. 返回集合、集合替代项、包装器和流的存储库方法保证永远不会返回null而是相应的空表示。 有关详细信息,请参阅“存储库查询返回类型”。spring-doc.cadn.net.cn

可空性注释

JSpecify

与 Spring Framework 7 和 Spring Data 4 一样,您可以使用 JSpecify 来表达存储库方法的可空性约束。 JSpecify 很好地集成到 IntelliJ 和 Eclipse 中,提供了一种工具友好的方法和选择加入null在运行时检查,如下所示:spring-doc.cadn.net.cn

@NullMarked在包级别通过package-info.java文件
@NullMarked
package org.springframework.core;

import org.jspecify.annotations.NullMarked;

在属于包的各种 Java 文件中,可为 null 类型的用法是显式定义的@Nullable. 建议在相关类型之前指定此注释。spring-doc.cadn.net.cn

例如,对于字段:spring-doc.cadn.net.cn

private @Nullable String fileEncoding;

或者对于方法参数和返回值:spring-doc.cadn.net.cn

public static @Nullable String buildMessage(@Nullable String message,
                                            @Nullable Throwable cause) {
    // ...
}

重写方法时,空性注释不会继承自超类方法。 这意味着,如果您只想覆盖实现并保持相同的 API null 性,则应重复这些 null 性注释。spring-doc.cadn.net.cn

使用数组和变量,您需要能够区分元素的空性与数组本身的空性。 请注意 Java 规范定义的语法,这最初可能会令人惊讶:spring-doc.cadn.net.cn

Java 规范还强制使用@Target(ElementType.TYPE_USE)喜欢 JSpecify@Nullable应在最后一个.具有内部或完全合格类型:spring-doc.cadn.net.cn

@NonNull@NullUnmarked对于典型用例来说,应该很少需要。spring-doc.cadn.net.cn

Spring Framework 可空性和 JSR-305 注释

您可以使用 Spring Framework 的可空性注释来表达存储库方法的可空性约束。spring-doc.cadn.net.cn

与 Spring Framework 7 一样,Spring 的可空性注释已被弃用,取而代之的是 JSpecify。 有关更多信息,请参阅有关从 Spring 空安全注释迁移到 JSpecify 的框架文档。

它们提供了一种工具友好的方法和选择加入null在运行时检查,如下所示:spring-doc.cadn.net.cn

Spring 注解使用 JSR 305 注解(一种休眠但广泛使用的 JSR)进行元注解。 JSR 305 元注解允许工具提供商(例如 IDEAEclipseKotlin)以通用方式提供空安全支持,而无需对 Spring 注解的支持进行硬编码。 要启用查询方法的可空性约束的运行时检查,您需要使用 Spring 的@NonNullApipackage-info.java,如以下示例所示:spring-doc.cadn.net.cn

package-info.java

一旦非 null 默认值就位,存储库查询方法调用将在运行时验证可空性约束。 如果查询结果违反定义的约束,则会引发异常。 当该方法返回null但声明为不可为 null(在存储库所在的包上定义的注释的默认值)。 如果要再次选择加入可为 null 的结果,请有选择地使用@Nullable在个人方法上。 使用本节开头提到的结果包装器类型将继续按预期工作:空结果被转换为表示缺席的值。spring-doc.cadn.net.cn

以下示例显示了刚才描述的许多技术:spring-doc.cadn.net.cn

使用不同的可空性约束
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 存储库驻留在我们定义了非空行为的包(或子包)中。
2 抛出一个EmptyResultDataAccessException当查询未产生结果时。 抛出一个IllegalArgumentExceptionemailAddress交给方法的null.
3 返回null当查询未产生结果时。 也接受null作为emailAddress.
4 返回Optional.empty()当查询未产生结果时。 抛出一个IllegalArgumentExceptionemailAddress交给方法的null.

基于 Kotlin 的存储库中的可空性

Kotlin 将可空性约束的定义融入到语言中。 Kotlin 代码编译为字节码,字节码不是通过方法签名来表达可空性约束,而是通过编译的元数据来表达可空约束。 确保包含kotlin-reflectJAR 来启用对 Kotlin 的可空性约束的自省。 Spring Data 存储库使用语言机制来定义这些约束以应用相同的运行时检查,如下所示:spring-doc.cadn.net.cn

在 Kotlin 代码库上使用可空性约束
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参数并返回null如果查询未产生结果。