Search code examples
springspring-mvchibernate-validator

Spring/Hibernate - validating groups manually and return a BindingResult


I want to manually validate (not using @Valid or @Validated) using groups and return a BindingResult.

I have a spring validator configured

  <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" >
    <property name="validationMessageSource" ref="messageSource"/>
  </bean> 

And this is the class that does the validation, it works but notice that groups is not being used.

@Component
public class ObjectValidatorImpl implements ObjectValidator {
    private final Validator validator;

    @Autowired
    public ObjectValidatorImpl(final Validator validator) {
        super();
        this.validator = validator;
    }

    @Override
    public final <T> BindingResult getBindingResults(
               final T objectToValidate, final Class<?>...groups) {
        final DataBinder binder = new DataBinder(objectToValidate);
        binder.setValidator(validator);

        //ideally, I would like to set the groups on the binder here like
        //binder.setGroups(groups);

        binder.validate();
        return binder.getBindingResult();
    }
}

I cant figure out how to get the Validator to use the groups, the seems to be no method for it.

I would like to call it like this.

objectValidator.validate(myObject, Class1.class, Class2.class)

Solution

  • I had a similar issue, and ended up extending the SpringValidatorAdapter class so that I could perform the validation and specify the groups.

    ExtendedSpringValidatorAdapter adapter = new ExtendedSpringValidatorAdapter(validator);
    adapter.validate(objectToValidate, bindingResult, Class1.class, Class2.class);
    

    Here is the definition of the extended validator:

    package com.example.validator;
    
    import org.springframework.beans.NotReadablePropertyException;
    import org.springframework.validation.Errors;
    import org.springframework.validation.FieldError;
    import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.Validator;
    import javax.validation.groups.Default;
    import java.util.Set;
    
    public class ExtendedSpringValidatorAdapter extends SpringValidatorAdapter {
    
        // ========================================================================
        // ========================================================================
        // ========================================================================
        public ExtendedSpringValidatorAdapter(Validator targetValidator) {
            super(targetValidator);
        }
    
        // ========================================================================
        // ========================================================================
        // ========================================================================
        public void validate(Object target, Errors errors, Class<?>... groups) {
    
            if (groups == null || groups.length == 0 || groups[0] == null) {
                groups = new Class<?>[]{Default.class};
            }
    
            Set<ConstraintViolation<Object>> result = validate(target, groups);
            for (ConstraintViolation<Object> violation : result) {
                String field = violation.getPropertyPath().toString();
                FieldError fieldError = errors.getFieldError(field);
                if (fieldError == null || !fieldError.isBindingFailure()) {
                    try {
                        errors.rejectValue(field,
                                violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(),
                                getArgumentsForConstraint(errors.getObjectName(), field, violation.getConstraintDescriptor()),
                                violation.getMessage());
                    } catch (NotReadablePropertyException ex) {
                        throw new IllegalStateException("JSR-303 validated property '" + field +
                                "' does not have a corresponding accessor for Spring data binding - " +
                                "check your DataBinder's configuration (bean property versus direct field access)", ex);
                    }
                }
            }
        }
    }