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

如何先校验@NotNull再执行@AssertTrue校验?

解决DTO校验中@NotNull与自定义方法校验的冲突问题

问题原因

Hibernate Validator在执行校验时,会同时触发字段注解(如@NotNull)和类中的方法级校验逻辑。当anInt为null时,@NotNull的校验还未拦截null值,自定义校验方法isIntCustomValid就会尝试访问null的anInt,从而抛出HV000090: Unable to access错误。

优雅解决方案

方案1:在自定义校验方法中兼容null场景

直接修改自定义校验方法,先判断字段是否为null,若为null则返回true(不触发该方法的校验失败),让@NotNull专门处理null的情况。这种方式无需额外接口,代码改动最小:

@Data
public class Dto {

    @NotNull
    private Integer anInt;

    @AssertTrue
    public boolean isIntCustomValid() {
        // 字段为null时,交由@NotNull处理,本方法不触发校验失败
        if (anInt == null) {
            return true;
        }
        return anInt == 123 || anInt == 999;
    }

}

方案2:整合校验逻辑为自定义字段注解

如果希望代码更紧凑,可以自定义一个字段级注解,将@NotNull和自定义取值校验逻辑整合在一起:

  1. 定义自定义校验注解:
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = IntValueValidator.class)
@NotNull // 整合非null校验逻辑
public @interface ValidIntValue {
    String message() default "值必须为123或999";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
  1. 实现校验器:
public class IntValueValidator implements ConstraintValidator<ValidIntValue, Integer> {
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        // 非null校验已由@NotNull完成,只需校验取值范围
        return value == 123 || value == 999;
    }
}
  1. 修改DTO:
@Data
public class Dto {

    @ValidIntValue(message = "anInt不能为空,且值必须是123或999")
    private Integer anInt;

}

这样只需一个注解就能完成两项校验,代码更简洁,也避免了分组接口的冗余。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 18:01:24