如何先校验@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和自定义取值校验逻辑整合在一起:
- 定义自定义校验注解:
@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 {}; }
- 实现校验器:
public class IntValueValidator implements ConstraintValidator<ValidIntValue, Integer> { @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { // 非null校验已由@NotNull完成,只需校验取值范围 return value == 123 || value == 999; } }
- 修改DTO:
@Data public class Dto { @ValidIntValue(message = "anInt不能为空,且值必须是123或999") private Integer anInt; }
这样只需一个注解就能完成两项校验,代码更简洁,也避免了分组接口的冗余。
内容的提问来源于stack exchange,提问作者jim jones
相关产品推荐
相关产品推荐

