Spring Validation - Class level validation to addr

2019-05-18 14:35发布

问题:

If we define a class level validation annotation, such as one which compare fields and have a ConstraintValidator like this:

public class ComparisonValidator implements ConstraintValidator<ValueMatches, Object>
{
    private String[] fields;

    @Override
    public void initialize(final ValueMatches constraintAnnotation) {
        fields = constraintAnnotation.fields();
    }

    @Override
    public boolean isValid(final Object value, final ConstraintValidatorContext context) {
        if (fields.length == 0) {
            return true;
        }

        final BeanWrapperImpl beanWrapper = new BeanWrapperImpl(value);
        final Object comparisonValue = beanWrapper.getPropertyValue(fields[0]);

        for (int i = 1; i < fields.length; i++) {
            final Object fieldValue = beanWrapper.getPropertyValue(fields[i]);

            if (!comparisonValue.equals(fieldValue)) {
                return false;
            }
        }

        return true;
    }
}

We well produce a Global validation error, accessible via Thymeleaf using: ${#fields.errors('global')}

Now, how can I identify that error and understand it is the specific comparison error? I mean, after all we get a message for global errors, or am I wrong?

回答1:

Damn you, Spring documentation! It is fairly simple, but not really understandable.

@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
    if (fields.length > 0) {
        final BeanWrapperImpl beanWrapper = new BeanWrapperImpl(value);
        final Object comparisonValue = beanWrapper.getPropertyValue(fields[0]);

        for (int i = 1; i < fields.length; i++) {
            if (!comparisonValue.equals(beanWrapper.getPropertyValue(fields[i]))) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate(errorMessage).addPropertyNode(fields[0]).addConstraintViolation();
                return false;
            }
        }
    }

    return true;
}

The method disableDefaultConstraintViolation() tells the ConstrainValidatorContext to not produce the constraint violation object by using the annotation itself.

You can then produce a custom constraint violation via the buildConstraintViolationWithTemplate() method.