How to create custom validations in Spring MVC

How to create custom validations in Spring MVC

In Spring MVC, @AssertTrue annotation helps us to create custom validations for HTTP requests.

For example, in Greeting class, “message" is required if “to" is not empty. You can implement this constraint by using @AssertTrue annotation. You need to create a method implementing check logic and add @AssertTrue annotation to the method.

Note that the name of a method with @AssertTrue must start with “is" or “get".

import lombok.Data;
import org.springframework.util.StringUtils;

import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Min;

@Data
public class Greeting {

    private String to;
    private String message;

  // Custom validation
    @AssertTrue(message = "message must not be empty if to is not empty.")
    public boolean isMessageNotEmptyIfToPresents() {

        if (StringUtils.isEmpty(to)) {
            return true;
        }

        return !StringUtils.isEmpty(message);
    }
}

How to handle validation errors with @RestControllerAdvice

In Spring MVC, you can implement a common exception handler with @RestControllerAdvice. MethodArgumentNotValidException is thrown when validation errors occur for HTTP requests.

Information of validation errors is contained in BindingResult of MethodArgumentNotValidException.

The following sample code handles MethodArgumentNotValidException and return an error response that contains all error messages of BindingResult. The error messages are joined with a comma.

import java.util.stream.Collectors;

@RestControllerAdvice
public class ErrorController {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleException(MethodArgumentNotValidException e) {

        // Join all messages of BindingResult with a comma
        var response = new ErrorResponse("error", e.getBindingResult().getAllErrors()
                .stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining(",")));
        return response;
    }

    @Data
    @AllArgsConstructor
    private static class ErrorResponse {

        private String id;
        private String message;
    }
}