构建Dynamic ConstraintViolation错误消息

时间:2014-05-16 19:13:23

标签: hibernate validation bean-validation

我编写了一个由自定义ConstraintValidator实现的验证注释。我还想生成非常具体的ConstraintViolation对象,这些对象使用在消息插值期间验证过程中计算的值。

public class CustomValidator 
  implements ConstraintValidator<CustomAnnotation, ValidatedType> {

...
  @Override
  public boolean isValid(ValidatedType value, ConstraintValidatorContext context) {
    // Figure out that the value is not valid.
    // Now, I want to add a violation whose error message requires arguments.
  }
}

我的消息来源中的假设错误消息:

CustomAnnotation.notValid = The supplied value {value} was not valid because {reason}.

传递给isValid方法的上下文提供了一个用于构建约束违规的接口,并最终将其添加到上下文中。但是,我似乎无法弄清楚如何使用它。根据我正在使用的版本documention,我可以将bean和属性节点添加到违规中。这些是我可以为违规定义指定的唯一其他详细信息,但我不明白它们如何映射到错误消息中的参数。

百万美元问题:如何使用自定义验证程序将动态参数传递给我的验证错误消息?我想填写{value}{reason}字段用于构建违规行为的ConstraintValidatorContext界面。

获取消息源的实例并在自定义验证器中插入消息不是一个选项 - 无论如何都会对来自验证的消息进行插值,并且内部插值将导致某些消息被插值两次,可能会消除转义单引号或我的消息定义文件中具有特殊含义的其他字符。

2 个答案:

答案 0 :(得分:11)

使用标准化的Bean Valiation API是不可能的,但在Hibernate Validator中有一种方法,即BV参考实现。

您需要将ConstraintValidatorContext打开到HibernateConstraintValidatorContext中,以便您访问addExpressionVariable()方法:

public class MyFutureValidator implements ConstraintValidator<Future, Date> {

    public void initialize(Future constraintAnnotation) {}

    public boolean isValid(Date value, ConstraintValidatorContext context) {
        Date now = GregorianCalendar.getInstance().getTime();

        if ( value.before( now ) ) {
            HibernateConstraintValidatorContext hibernateContext =
                context.unwrap( HibernateConstraintValidatorContext.class );

            hibernateContext.disableDefaultConstraintViolation();
            hibernateContext.addExpressionVariable( "now", now )
                .buildConstraintViolationWithTemplate( "Must be after ${now}" )
                .addConstraintViolation();

            return false;
        }

        return true;
    }
}

参考指南有一些more details

答案 1 :(得分:1)

如果您使用消息代码,则可以在其中添加{0}之类的内容。

例如:“字段{0}不能为空。”

然后使用hibernateContext.addMessageParameter("0", fieldName); 而不是addExpressionVariable(...)

这对我有用。