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

如何让@NotNull注解在自定义校验器MyDtoConstraint前执行?

问题原因与解决方案

为什么自定义校验器会先执行?

核心问题出在组序列的触发逻辑和嵌套校验的时机:

  • 你给MyDto定义的组序列是LightErrors → HeavyError → 默认组,但MyDto本身没有属于LightErrors组的直接约束,只有类级的MyDtoConstraint属于HeavyError组。
  • 校验器处理MyDto的LightErrors组时,因为当前对象没有该组的约束,会直接跳过这个组,进入HeavyError组的处理。
  • 在HeavyError组阶段,校验器先执行类级的MyDtoConstraintValidator(此时MyDto的HeavyError组没有属性级约束,直接走类级校验),之后才会触发commission对象的HeavyError组校验——但commission的@NotNull属于LightErrors组,根本不会在这个阶段执行。
  • 只有当校验器处理到MyDto的默认组时,才会按照MyCommissionDto的组序列执行它的LightErrors组约束,但这已经在自定义校验器执行之后了。

简单说:你的组序列逻辑没触发嵌套对象的LightErrors组校验,导致@NotNull被延迟到默认组阶段,而自定义校验器在HeavyError组提前执行了。

如何让@NotNull先执行?

有两种可靠的解决方式:

方案1:给MyDto的commission属性加LightErrors组的空约束

在MyDto的commission属性上添加一个属于LightErrors组的无实际校验逻辑的约束,目的是让校验器在处理LightErrors组时,触发嵌套对象的同组校验:

@GroupSequence(value = {ValidationGroup.LightErrors.class, ValidationGroup.HeavyError.class, MyDto.class})
@MyDtoConstraint(groups = ValidationGroup.HeavyError.class)
public class MyDto {
    @Valid
    @NotNull(groups = ValidationGroup.LightErrors.class, message = "") // 仅用于触发LightErrors组的嵌套校验
    private MyCommissionDto commission;
}

这样,当MyDto的LightErrors组被处理时,会触发commission的LightErrors组校验,先执行@NotNull(type),之后才进入HeavyError组执行自定义校验器。

方案2:显式指定校验组为LightErrors和HeavyError

在Spring的校验入口(比如Controller)显式指定要校验的组,让组序列严格按顺序执行:

@PostMapping("/submit")
public ResponseEntity<?> submit(
    @Validated({ValidationGroup.LightErrors.class, ValidationGroup.HeavyError.class}) 
    @RequestBody MyDto dto
) {
    // 业务逻辑
    return ResponseEntity.ok("success");
}

此时校验器会先完整执行LightErrors组的所有约束(包括嵌套的MyCommissionDto的@NotNull),确认无错后才会执行HeavyError组的自定义校验器。

补充说明

  • 组序列的核心是前一组所有约束通过后,才执行下一组,但前提是每个组都有对应的触发点(当前对象的约束或@Valid嵌套的同组约束)。
  • 嵌套对象的组序列只作用于自身校验,不影响父对象的组执行顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 15:42:14