javaspringvalidationspring-validatorspring-validation

Possible to overwrite the default validation message in Spring’s Validator?


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;

    ...
}

Solution

  • 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;
    
        ...
    }