java - 如何使用自定义 ConstraintValidator 将 ConstraintViolations 添加到索引 i 处的列表元素

标签 java list validation thymeleaf javabeans

我目前正在开发一个自定义 ConstraintValidator 来检查具有与其关联的时间跨度的对象数组,以了解其时间跨度的重叠情况。验证逻辑正在工作,但是,我不确定如何向违反验证逻辑的每个对象添加“此对象的时隙与另一个对象的时隙重叠”消息。

我尝试了此处描述的几种方法: https://docs.oracle.com/javaee/7/api/javax/validation/ConstraintValidatorContext.html

特别是 buildConstraintViolationWithTemplate 方法文档中描述的内容。

这是代码的相关部分:

@Override
public boolean isValid(List<Shift> shifts, ConstraintValidatorContext context) {

List<Integer> overlappingShiftIndices = determineOverlappingShifts(shifts);

if (!overlappingShiftIndices.isEmpty()) {
  log.debug("Overlap validation failed.");

  context.disableDefaultConstraintViolation();
  // Moving the error from form-level to fields
  for (int index : overlappingShiftIndices) {
    context.buildConstraintViolationWithTemplate("{com.generali.standbyscheduler.validation.shiftlist.overlap}")
           .addBeanNode()
           .inIterable().atIndex(index)
           .addConstraintViolation();
  }

  return false;
}

log.debug("Overlap validation succeeded.");
return true;
}

如您所见,我在这里尝试了 .addBeanNode().inIterable().atIndex(index) 方法。查看 ConstraintViolation 时,属性路径显示为 list[index]。这是正确的吗?

我计划使用它来访问 Thymeleaf 模板中的 BindingResult 中确定的违规行为,并且不确定是否可以通过这种方式访问​​违规行为。该列表将是另一个 bean 的属性,因此我希望使用像 propertyNameOfList[index] 这样的路径来读取违规行为。或者是 propertyNameOfList.list[index] 还是其他?

最佳答案

当尝试验证对象列表中的某些字段是否唯一时,我遇到了同样的问题。我自己的解决方案(我在互联网上找不到:/):

您必须覆盖当前的 PropertyNode 并使用 .addPropertyNode(null).inIterable().atIndex(index) 添加索引号。示例:

约束注释:

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueBusinessIndexValidator.class)
public @interface UniqueEntries {

    String message() default ValidationMessages.REQUIRED_UNIQUE_INDEX;
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

约束 validator :

public class UniqueBusinessIndexValidator implements ConstraintValidator<UniqueEntries, List<HasBusinessIndex>> {

    @Override
    public boolean isValid(List<HasBusinessIndex> collection, ConstraintValidatorContext context) {
        if (collection == null || collection.isEmpty()) {
            return true;
        }

        Map<String, List<Integer>> indexesMap = new HashMap<>();
        for (int runner = 0; runner < collection.size(); runner++) {
            String businessIndex = collection.get(runner).getBusinessIndex();
            if (indexesMap.containsKey(businessIndex)) {
                indexesMap.get(businessIndex).add(runner);
            } else {
                indexesMap.put(businessIndex, new ArrayList<>(List.of(runner)));
            }
        }

        boolean isValid = indexesMap.values().stream().noneMatch(indexes -> indexes.size() > 1);
        if (!isValid) {
            indexesMap.values()
                      .stream()
                      .filter(index -> index.size() > 1)
                      .forEach(index -> addUniqueBusinessIndexkennungViolation(context, index));
        }
        return isValid;
    }

    private void addUniqueBusinessIndexkennungViolation(ConstraintValidatorContext context, List<Integer> indexes) {
        for (Integer index : indexes) {
            context.buildConstraintViolationWithTemplate(ValidationMessages.REQUIRED_UNIQUE_INDEX)
                   .addPropertyNode(null)
                   .inIterable()
                   .atIndex(index)
                   .addPropertyNode("businessIndex")
                   .addConstraintViolation()
                   .disableDefaultConstraintViolation();
        }
    }

关于java - 如何使用自定义 ConstraintValidator 将 ConstraintViolations 添加到索引 i 处的列表元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55457664/

相关文章:

html - HTML 5 的输入类型电子邮件如何工作并且可靠吗?

java - Java 中的私有(private)变量和 C++ 结构中的私有(private)变量有什么区别?

java - Bluemix Cloud Foundry : JAVA_OPTS $PORT is blank

c# - 列表与数组 : One-To-Many and Has-A Relationship

asp.net-mvc - Entity Framework 4.1 - 现有数据库的代码优先,如何定义类,使用属性或 EntityTypeConfiguration?有什么不同?

c# - 路由参数在 WebApi 中不起作用

java - 我不知道为什么我的对象变成空的。另外,为什么 repaint() 并不总是调用 paintComponent()?

java - 如何使用 spring boot 和 maven 测试微服务

r - 从另一个列表(嵌套列表)的列表元素开始创建一个新列表

Python从文本文件中删除标点符号