Serhii
Serhii

Reputation: 7543

Spring Controller double validation for @ModelAttribute object

I have implemented controller with method:

public Page<EventDto> search(@ModelAttribute @Valid EventsCriteria criteria){...}

It works. EventsCriteria did not have special separate validator for itself, because it has inner annotation checkers like @NotNull @NotEmpty. Right now situation is changed and it's not enough to have only this validators. so I've added and registered correspond service to verify some sates.

I want service to verify additional composite cases and single validation like before. But my single inner annotation checkers like @NotNull @NotEmpty do not work any more.

Am I configured something incorrectly or it can't work in in same time(specified service and inner checkers)?

My validator example (as it was asked in comments)

There are nothing special, if you know spring, so I missed this part like unimportant to concentrate your attention on my question.

@Component
public class EventsCriteriaValidator implements Validator {

    public static final String INVALID_RAGE_PARAMETERS_SPECIFIED = "Invalid rage parameters: please specify " +
            "'from' and 'to' or page 'size";

    @Override
    public boolean supports(Class<?> clazz) {
        return clazz.isAssignableFrom(EventsCriteria.class);
    }

    @Override
    public void validate(Object target, Errors errors) {
        EventsCriteria toValidate = (EventsCriteria) target;
        validateComplexRestriction(toValidate, errors);
    }

    private void validateComplexRestriction(EventsCriteria toValidate, Errors errors) {
        if (toValidate.isRangeEmpty() && toValidate.getSize() == 0) {
            errors.rejectValue(SIZE_FIELD, null, INVALID_RAGE_PARAMETERS_SPECIFIED);
        }
    }

}

Upvotes: 1

Views: 842

Answers (3)

e2rabi
e2rabi

Reputation: 4838

Let assume that your EventsCriteria contains two fields so inside your validate method you can validate those field using : ValidationUtils (org.springframework.validation.ValidationUtils)

 @Override
    public void validate(Object target, Errors errors) {
        EventsCriteria eventsCriteria= (EventsCriteria) target;
        ValidationUtils.rejectIfEmpty(errors, "field1", "eventsCriteria.field1.empty");
        ValidationUtils.rejectIfEmpty(errors, "field2", "eventsCriteria.field2.empty");
    }

and in your messages.properties

eventsCriteria.field1.empty = Enter a valid value for field 1.
eventsCriteria.field2.empty = Enter a valid value for field 2.

and in your configuration class add this bean:

 @Bean
   public MessageSource messageSource() {
      ResourceBundleMessageSource source = new ResourceBundleMessageSource();
      source.setBasename("messages");
      return source;
   }

Upvotes: 1

gkatiforis
gkatiforis

Reputation: 1652

Edited:

If you want both custom and default validation you can use addValidators in initBinder to add your custom validations. This way default validations will not be deleted.

@Controller
public class MyController
{
    @Autowired
    private EventsCriteriaValidator validator;

    @InitBinder
    protected void initBinder(final WebDataBinder binder)
    {
         binder.addValidators(validator);
    }

  public Page<EventDto> search(@ModelAttribute @Valid EventsCriteria   criteria, BindingResult result){

     if (result.hasErrors()) {
        // validation failed

     } else {
        //validation passed   
     }
  }

}

Upvotes: 0

vl4d1m1r4
vl4d1m1r4

Reputation: 1781

Just make your Validator extend LocalValidatorFactoryBean and then call super.validate(target, errors) in your validate method like this:

@Override
public void validate(Object target, Errors errors) {
   super.validate(target, errors);

   EventsCriteria toValidate = (EventsCriteria) target;
   validateComplexRestriction(toValidate, errors);
}

Upvotes: 0

Related Questions