DEV Community

Salad Lam
Salad Lam

Posted on

Spring MVC: Controller level model binding validation

Notice

I wrote this article and was originally published on Qiita on 9 July 2021.


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

}
Enter fullscreen mode Exit fullscreen mode

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())
    ...
}
Enter fullscreen mode Exit fullscreen mode

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
        ...
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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.

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay