You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Record封装查询参数时@NotNull校验失效问题

Java Record字段校验注解(@NotNull/@NotBlank)不生效导致NPE的解决方案

当使用Java Record封装请求查询参数时,字段上的@NotNull、@NotBlank注解未生效。缺少必填参数的请求未返回预期的400 Bad Request,而是因空指针异常(NPE)返回500错误——自定义类级校验器执行时,访问了未校验的null字段。

场景示例:

  • 有效请求:http://localhost:8080/api/client?searchKey=NAME&value=John
  • 无效请求(应返回400但返回500):
    • http://localhost:8080/api/client?searchKey=NAME(缺少value参数)
    • http://localhost:8080/api/client?value=John(缺少searchKey参数)

1. 确保引入Bean Validation依赖

Spring Boot项目需引入spring-boot-starter-validation,提供Hibernate Validator等校验实现:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

2. 调整类级校验的执行顺序

自定义类级注解会优先于字段级注解执行,导致字段未校验就进入校验器引发NPE。通过@GroupSequence指定校验顺序,让字段级校验(默认组)先执行:

修改@ValidPersonSearchParameter注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PersonSearchParameterValidator.class)
@GroupSequence({Default.class, ValidPersonSearchParameter.class})
public @interface ValidPersonSearchParameter {
    String message() default "Invalid search parameter";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

3. 确保Record字段注解被正确识别

Hibernate Validator 6.1+已原生支持Java Record的组件注解,无需额外修改Record。若使用旧版本,需显式在构造方法参数上添加校验注解:

// 旧版本兼容写法(可选)
public record PersonSearchParameters(
        @NotNull SearchKey searchKey,
        @NotBlank String value
) {
    public PersonSearchParameters(@NotNull SearchKey searchKey, @NotBlank String value) {
        this.searchKey = searchKey;
        this.value = value;
    }
}

4. 控制器校验配置保持正确

控制器类上的@Validated启用Spring校验,方法参数上的@Valid触发Record的字段校验:

@RestController
@RequestMapping(value = "/api/client", produces = APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
@Validated
public class PersonController {

    @GetMapping
    public PersonInfoResponse getPersonInfo(@Valid @NotNull PersonSearchParameters parameters) {
        // 业务逻辑
    }
}

5. 优化自定义校验器逻辑

字段级校验通过后,自定义校验器无需再处理null值,可直接执行业务校验:

public class PersonSearchParameterValidator implements ConstraintValidator<ValidPersonSearchParameter, PersonSearchParameters> {

    @Override
    public boolean isValid(PersonSearchParameters parameters, ConstraintValidatorContext context) {
        // 此时searchKey和value已通过@NotNull/@NotBlank校验,无需判空
        // 执行自定义校验逻辑,例如:检查searchKey与value的匹配规则
        return true; // 根据实际业务返回校验结果
    }
}

原理说明

  • 未调整校验顺序时,类级校验器先执行,此时字段未经过@NotNull/@NotBlank校验,访问null字段直接抛出NPE。
  • 通过@GroupSequence指定顺序后,字段级校验(默认组)优先执行,若参数缺失,直接返回400 Bad Request,不会进入自定义校验器。
  • 确保依赖正确是Bean Validation生效的基础,Spring Boot starter已整合所需的校验组件。

内容的提问来源于stack exchange,提问作者stakeika

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 07:08:15