Javax验证:地图的约束违规

时间:2012-07-27 09:55:29

标签: java validation map bean-validation hibernate-validator

我将Map用于本地化值,其中locale作为键,String作为值。对于必填字段,我需要检查至少设置了所需的语言环境 - 或者至少设置了一些值。我已经实现了验证注释,可以在这样的Map字段和相应的验证器上使用。问题是,如何报告缺失值? 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。

2 个答案:

答案 0 :(得分:3)

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

这就是我的所作所为:

我使用了一个“embeddable”bean,而不是Map,它使用了所有支持的语言环境的实际字段(例如LocalizedString(String fi,String en等)。然后报告违规行为:

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

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

Spring的LocalValidatorFactoryBean或Hibernate Validator不能正确支持嵌入式验证。由于同一组件在具有不同验证要求的不同位置使用,我不能在组件本身内使用@Valid实际验证注释 - 至少不支持@Valid上的验证组。

Spring的LocalValidatorFactoryBean或Hibernate Validator的问题是invalidValue的{​​{1}}是LocalizedString(“field”)而不是报告的错误嵌套字段的值(“field”。网络“)。幸运的是,这可以通过覆盖ConstraintViolation来删除“使用ConstraintViolation中的无效值自定义FieldError注册”并简单地通过

报告错误来解决
LocalValidatorFactoryBean.processConstraintViolations

这样Spring就可以使用给定的errors.rejectValue(field, errorCode, errorArgs, violation.getMessage()); 解析invalidValue

答案 1 :(得分:0)

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

Validation of a Collection

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

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

 @LocalizationRequired
 List<LocaleToString> locales;

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