I am learning how to effectively use the Spring’s Bean Validator in my REST project.
I have the following POJO:
public class Project {
@NotBlank(message = "%s is mandatory")
private String projectName;
@NotBlank(message = "%s is mandatory")
private String maintainerName;
@NotBlank(message = "%s is mandatory")
private String maintainerEmail;
...
}
And this is my GlobalExceptionHandler
that handles the MethodArgumentNotValidException
and generates a proper HTTP response based on the validation messages:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.warn(e.getMessage());
StringBuilder sb = new StringBuilder();
AtomicReference<String> separator = new AtomicReference<>("");
e.getBindingResult().getAllErrors().forEach((error) -> {
sb.append(separator.get());
sb.append(String.format(error.getDefaultMessage(), ((FieldError) error).getField()));
separator.set(", ");
});
return new ResponseEntity<>(sb.toString(), HttpStatus.BAD_REQUEST);
}
}
The code above works properly and it generates the expected response:
HTTP/1.1 400
Content-Type: text/plain;charset=UTF-8
Content-Length: 57
Date: Mon, 16 Jun 2025 19:07:22 GMT
Connection: close
maintainerEmail is mandatory, maintainerName is mandatory
But, let's suppose I have ten POJOs with 50 fields that I would like to validate with the same @NotBlank(message = "%s is mandatory")
annotation. To write down 50 times the same
message = "%s is mandatory"
line looks like ugly for me.
Is that possible to overwrite Spring Validator’s default message to "%s is mandatory"
?
That could be so elegant solution instead of writing down the same error message string millions of time.
I would like to hardcode somehow my error message in a Spring config bean and have this simple code:
public class Project {
@NotBlank
private String projectName;
@NotBlank
private String maintainerName;
@NotBlank
private String maintainerEmail;
...
}
Option 1
If you use spring boot, you can create a file named ValidationMessages.properties
(or messages.properties
if you prefer) in your src/main/resources
directory, spring boot will automatically pick up this file.
In this file, you can override the default messages for any constraint. For @NotBlank, add:
jakarta.validation.constraints.NotBlank.message=%s is mandatory
This message will now be used for all fields annotated with @NotBlank, unless you override it at the field level.
And DTO:
public class Project {
@NotBlank
private String projectName;
@NotBlank
private String maintainerName;
@NotBlank(message = "Maintainer email is required") // if you want to override message from ValidationMessages.properties
private String maintainerEmail;
...
}
This option is also preferable from my point of view, as it allows us to override the value from the ValidationMessages.properties
file.
Option 2
As suggested in the comment by @dan1st, you could create your custom annotation, smth like this:
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.constraints.NotBlank;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({FIELD, ANNOTATION_TYPE, PARAMETER})
@Retention(RUNTIME)
@NotBlank(message = "%s is mandatory")
@Constraint(validatedBy = {})
public @interface Mandatory {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
And DTO:
public class Project {
@Mandatory
private String projectName;
@Mandatory
private String maintainerName;
@Mandatory
private String maintainerEmail;
...
}