Building Dynamic ConstraintViolation Error Messages

£可爱£侵袭症+ 提交于 2020-12-28 20:53:38

问题


I've written a validation annotation implemented by a custom ConstraintValidator. I also want to generate very specific ConstraintViolation objects that use values computed during the validation process during message interpolation.

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.
  }
}

A hypothetical error message in my message source:

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

The context passed into the isValid method provides an interface for building up a constraint violation, and finally adding it to the context. However, I can't seem to figure out how to use it. According to this documention for the version I'm using, I can add bean and property nodes to the violation. These are the only additional details I can specify to the violation definition, but I don't understand how they might map to parameters in the error message.

Million dollar question: how can I pass dynamic parameters to my validation error messages using a custom validator? I would like to fill in those {value} and {reason} fields using the ConstraintValidatorContext's interface for building violations.

Obtaining an instance of the message source and interpolating the message within the custom validator is not an option - the messages coming out of validation get interpolated no matter what, and interpolating internally will result in some messages being interpolated twice, potentially annihilating escaped single quotes or other characters with special meanings in my message definitions file.


回答1:


That's not possible with the standardized Bean Valiation API, but there is a way in Hibernate Validator, the BV reference implementation.

You need to unwrap the ConstraintValidatorContext into a HibernateConstraintValidatorContext which gives you access to the addExpressionVariable() method:

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;
    }
}

The reference guide has some more details.




回答2:


If you use message codes you can simply add something like {0} in them.

For example: "The field {0} must not be empty."

And then use hibernateContext.addMessageParameter("0", fieldName); instead of addExpressionVariable(...).

That worked for me.



来源:https://stackoverflow.com/questions/23702975/building-dynamic-constraintviolation-error-messages

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!