To perform model binding validation of controller, one of the solution is register validator on controller.
#1. Write your own validator
You validator should extend org.springframework.validation.Validator interface. Below is a example.
public class MessageDtoValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return MessageDto.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
// target is model being checked and errors register into errors instance
ValidationUtils.rejectIfEmpty(errors, "publishDate", "publishDate.empty");
ValidationUtils.rejectIfEmpty(errors, "description", "description.empty");
}
}
#2. Register your validator
You should register your validator on function annotated with org.springframework.web.bind.annotation.InitBinder annotation with org.springframework.validation.DataBinder.setValidator(Validator) function.
// Call everytime when recevies request
@InitBinder
public void initBinder(WebDataBinder binder) {
...
binder.setValidator(new MessageDtoValidator())
...
}
org.springframework.validation.Validator.supports(Class>) of your validator will be called when calling setValidator() to verify is your validator supports model binded.
#3. Specify model argument you want to verify and define corresponding action
You should add javax.validation.Valid (or org.springframework.validation.annotation.Validated) annotation in addition with org.springframework.web.bind.annotation.ModelAttribute annotation on model argument you want to verify. And specify actions when binding error is found.
@PostMapping("/{messageId}/save")
public String saveEditMessage(@PathVariable("messageId") long id, @Valid @ModelAttribute MessageDto message, BindingResult errors) {
if (errors.hasErrors()) {
// your action
...
}
}
After binding model, framework will check if validation annotation exists on model argument by org.springframework.web.method.annotation.ModelAttributeMethodProcessor.determineValidationHints(Annotation) function.
/**
* Determine any validation triggered by the given annotation.
* @param ann the annotation (potentially a validation annotation)
* @return the validation hints to apply (possibly an empty array),
* or {@code null} if this annotation does not trigger any validation
* @since 5.1
*/
@Nullable
private Object[] determineValidationHints(Annotation ann) {
Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
if (hints == null) {
return new Object[0];
}
return (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
}
return null;
}
And then actual validation logic org.springframework.validation.Validator.validate(Object, Errors) will be called by org.springframework.web.method.annotation.ModelAttributeMethodProcessor.validateIfApplicable(WebDataBinder, MethodParameter) function.
#Example
You can find actual implementation from my notice board example application.