JSR 303 验证,如果一个字段等于“某物”,则这些其他字段不应为 null

2022-08-31 09:27:23

我想用JSR-303做一些自定义验证。javax.validation

我有一个领域。如果在此字段中输入了某个值,我想要求其他几个字段不是 。null

我试图弄清楚这一点。不知道我到底会怎么称呼它来帮助找到解释。

任何帮助将不胜感激。我对此很陌生。

目前,我正在考虑自定义约束。但我不确定如何从注释中测试依赖字段的值。基本上,我不确定如何从注释访问面板对象。

public class StatusValidator implements ConstraintValidator<NotNull, String> {

    @Override
    public void initialize(NotNull constraintAnnotation) {}

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if ("Canceled".equals(panel.status.getValue())) {
            if (value != null) {
                return true;
            }
        } else {
            return false;
        }
    }
}

这是给我带来麻烦的。不知道如何做到这一点。panel.status.getValue();


答案 1

定义必须验证为 true 的方法,并将注释放在其顶部:@AssertTrue

  @AssertTrue
  private boolean isOk() {
    return someField != something || otherField != null;
  }

该方法必须以“is”开头。


答案 2

在这种情况下,我建议编写一个自定义验证器,它将在类级别进行验证(以允许我们访问对象的字段),仅当另一个字段具有特定值时,才需要一个字段。请注意,您应该编写获取 2 个字段名称并仅使用这 2 个字段的通用验证程序。要要求多个字段,您应该为每个字段添加此验证程序。

使用以下代码作为想法(我还没有测试它)。

  • 验证器接口

    /**
     * Validates that field {@code dependFieldName} is not null if
     * field {@code fieldName} has value {@code fieldValue}.
     **/
    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Repeatable(NotNullIfAnotherFieldHasValue.List.class) // only with hibernate-validator >= 6.x
    @Constraint(validatedBy = NotNullIfAnotherFieldHasValueValidator.class)
    @Documented
    public @interface NotNullIfAnotherFieldHasValue {
    
        String fieldName();
        String fieldValue();
        String dependFieldName();
    
        String message() default "{NotNullIfAnotherFieldHasValue.message}";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
    
        @Target({TYPE, ANNOTATION_TYPE})
        @Retention(RUNTIME)
        @Documented
        @interface List {
            NotNullIfAnotherFieldHasValue[] value();
        }
    
    }
    
  • 验证器实现

    /**
     * Implementation of {@link NotNullIfAnotherFieldHasValue} validator.
     **/
    public class NotNullIfAnotherFieldHasValueValidator
        implements ConstraintValidator<NotNullIfAnotherFieldHasValue, Object> {
    
        private String fieldName;
        private String expectedFieldValue;
        private String dependFieldName;
    
        @Override
        public void initialize(NotNullIfAnotherFieldHasValue annotation) {
            fieldName          = annotation.fieldName();
            expectedFieldValue = annotation.fieldValue();
            dependFieldName    = annotation.dependFieldName();
        }
    
        @Override
        public boolean isValid(Object value, ConstraintValidatorContext ctx) {
    
            if (value == null) {
                return true;
            }
    
            try {
                String fieldValue       = BeanUtils.getProperty(value, fieldName);
                String dependFieldValue = BeanUtils.getProperty(value, dependFieldName);
    
                if (expectedFieldValue.equals(fieldValue) && dependFieldValue == null) {
                    ctx.disableDefaultConstraintViolation();
                    ctx.buildConstraintViolationWithTemplate(ctx.getDefaultConstraintMessageTemplate())
                        .addNode(dependFieldName)
                        .addConstraintViolation();
                        return false;
                }
    
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
                throw new RuntimeException(ex);
            }
    
            return true;
        }
    
    }
    
  • 验证器用法示例(休眠验证器>= 6,Java 8+)

    @NotNullIfAnotherFieldHasValue(
        fieldName = "status",
        fieldValue = "Canceled",
        dependFieldName = "fieldOne")
    @NotNullIfAnotherFieldHasValue(
        fieldName = "status",
        fieldValue = "Canceled",
        dependFieldName = "fieldTwo")
    public class SampleBean {
        private String status;
        private String fieldOne;
        private String fieldTwo;
    
        // getters and setters omitted
    }
    
  • 验证器用法示例(休眠验证器< 6;旧示例)

    @NotNullIfAnotherFieldHasValue.List({
        @NotNullIfAnotherFieldHasValue(
            fieldName = "status",
            fieldValue = "Canceled",
            dependFieldName = "fieldOne"),
        @NotNullIfAnotherFieldHasValue(
            fieldName = "status",
            fieldValue = "Canceled",
            dependFieldName = "fieldTwo")
    })
    public class SampleBean {
        private String status;
        private String fieldOne;
        private String fieldTwo;
    
        // getters and setters omitted
    }
    

请注意,验证器实现使用库中的类,但您也可以使用Spring Framework中的BeanWrapperImplBeanUtilscommons-beanutils

另请参阅这个精彩的答案:使用休眠验证器进行跨字段验证 (JSR 303)


推荐