Javax 验证:地图约束违规

问题描述 投票:0回答:3

我使用 Map 来获取本地化值,其中 locale 作为键, String 作为值。对于必填字段,我需要检查是否至少设置了必需的区域设置 - 或者至少设置了某个值。我已经实现了用于此类映射字段和相应验证器的验证注释。问题是,如何报告缺失值? UI 中用于绑定字段错误/值的属性路径每次都会出错:

// Domain object:
@LocalizationRequired
private Map<Locale, String> field;


// LocalizationRequiredValidator:
public boolean isValid(Map<Locale, String> map, ConstraintValidatorContext context) {
    if (requiredLocales.isEmpty()) {
        // Check that there exists any not null value
    } else {
        context.disableDefaultConstraintViolation();
        boolean valid = true;
        for (Locale requiredLocale : requiredLocales) { 
            if (map.get(requiredLocale) == null) { // e.g. fi
                valid = false;
                context.buildConstraintViolationWithTemplate("LocalizationRequired")
                // These end up in wrong property path:
                // .addNode(requiredLocale) 
                //    --> field.fi
                // .addNode("[" + requiredLocale + "]") 
                //    --> field.[fi]
                // .addNode(null).addNode(requiredLocale).inIterable() 
                //    --> field.fi
                // .addNode(null).addNode(null).inIterable().atKey(requiredLocale)
                //   --> field
                .addConstraintViolation();
            }
        }
        return valid;
    }
}

此错误的正确路径是“field[fi]”,但看来我只能访问索引子属性。在这种情况下,对象本身被索引。我正在使用 Hibernate Validator。

java validation dictionary bean-validation hibernate-validator
3个回答
3
投票

我无法找到一种方法来报告元素级别索引字段的错误。 - 规范中是否忽略了这一点?

这就是我所做的:

我没有使用 Map,而是使用了一个“可嵌入”bean,其中包含所有受支持语言环境的实际字段(例如 LocalizedString(String fi、String en 等)。然后报告了如下违规行为:

context.buildConstraintViolationWithTemplate("LocalizationRequired")
.addNode(requiredLocale)
.addConstraintViolation();

这在我们的情况下是可行的,因为我们有一组预定义的受支持语言,但它不能扩展到具有任意索引的索引字段。

此外,Spring 的

LocalValidatorFactoryBean
或 Hibernate Validator 都不能正确支持可嵌入的验证。由于同一组件在具有不同验证要求的不同地方使用,因此我无法将
@Valid
与组件本身内的实际验证注释一起使用 - 至少在不支持
@Valid
上的验证组的情况下无法使用。

Spring 的

LocalValidatorFactoryBean
或 Hibernate Validator 的问题在于
invalidValue
ConstraintViolation
是 LocalizedString(“field”),而不是报告的错误嵌套字段(“field.fi”)的值。幸运的是,这可以通过覆盖
LocalValidatorFactoryBean.processConstraintViolations
来解决,方法是删除“自定义 FieldError 注册,其值来自 ConstraintViolation”并简单地通过

报告错误
errors.rejectValue(field, errorCode, errorArgs, violation.getMessage());

这样 Spring 使用给定的

invalidValue
来解析
field


0
投票

这是一个非常有趣的问题。现在我没有时间亲自测试:(,但是这里的这个人:

集合验证

似乎能够验证元素集合。 因此,如果您切换到 Collection 而不是 Map(这应该相当容易),例如:

 class LocaleToString {
      private Locale locale;
      private String language;
 }

 @LocalizationRequired
 List<LocaleToString> locales;

我认为你应该能够实现你想要的。


0
投票

旧帖子,但我没有看到有人为地图添加答案。 如果您执行以下操作:

if (map.get(requiredLocale) == null) { // e.g. fi
  valid = false;
  context.buildConstraintViolationWithTemplate("LocalizationRequired")
         .addPropertyNode("<map value>")
         .inIterable().atKey(requiredLocale)
         .addConstraintViolation();
}

它将产生

field[fi].<map value>
,这与您在

中看到的属性格式相同
Map<Locale, @NotNull String>
© www.soinside.com 2019 - 2024. All rights reserved.