Spring Boot
Handle exceptions and perform validation in REST APIs using @ControllerAdvice, @ExceptionHandler, and @Valid
By Utility Zone · 2025-11-01T14:41:59.11049
Now I have comprehensive information to create a detailed guide on exception handling and validation in Spring Boot REST APIs. Let me generate the response.
Exception Handling and Validation in Spring Boot REST APIs
Handling exceptions and validating input data are critical aspects of building robust REST APIs with Spring Boot. Spring provides powerful annotations like @ControllerAdvice, @ExceptionHandler, and @Valid to implement centralized exception handling and automatic validation seamlessly.
Setting Up Dependencies
First, ensure you have the necessary dependency in your pom.xml. For Spring Boot 2.3+, you need to explicitly add the validation starter:1
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
The validation starter includes Hibernate Validator, the reference implementation of Jakarta Bean Validation.21
Understanding the Key Annotations
@ControllerAdvice vs @RestControllerAdvice
Both annotations enable global exception handling across all controllers, but with a key difference:34
- @ControllerAdvice: Used for traditional Spring MVC applications that return views. Requires
@ResponseBodyon handler methods to return JSON responses - @RestControllerAdvice: A specialized version that combines
@ControllerAdvice+@ResponseBody, designed specifically for RESTful services that return JSON/XML directly45
@RestControllerAdvice = @ControllerAdvice + @ResponseBody
@ExceptionHandler
This annotation marks methods that handle specific exceptions. Methods annotated with @ExceptionHandler are automatically recognized by Spring as exception handlers. You can handle multiple exception types in a single method or create separate handlers for different exceptions.678
@Valid
This annotation triggers validation on annotated objects based on Jakarta Bean Validation constraints defined on the class fields. When validation fails, Spring automatically throws a MethodArgumentNotValidException.910
Implementing Bean Validation
Step 1: Add Validation Constraints to Your Entity/DTO
Apply validation annotations to your model fields:21
import jakarta.validation.constraints.*;
public class Employee {
@NotNull(message = "ID cannot be null")
private Long id;
@NotBlank(message = "First name is required")
@Size(min = 3, max = 20, message = "First name should be between 3 and 20 characters")
private String firstName;
@NotBlank(message = "Last name is required")
@Size(min = 3, max = 20, message = "Last name should be between 3 and 20 characters")
private String lastName;
@Email(message = "Email is invalid")
@NotBlank(message = "Email is required")
private String email;
@Min(value = 18, message = "Age must be at least 18")
@Max(value = 65, message = "Age must not exceed 65")
private Integer age;
@Pattern(regexp = "^[0-9]{10}quot;, message = "Phone number must be 10 digits")
private String phoneNumber;
// Getters and setters
}
Common Validation Annotations:11129
@NotNull: Field must not be null@NotBlank: String must not be null or empty (ignores whitespace)@NotEmpty: Collection/String must not be null or empty@Size(min, max): String/Collection size must be within range@Min(value)/@Max(value): Numeric value constraints@Email: Must be a valid email address@Pattern(regexp): Must match the specified regex@Positive/@Negative: Numeric sign validation@Past/@Future: Date must be in past/future
Step 2: Enable Validation in REST Controller
Use @Valid annotation with @RequestBody to trigger automatic validation:92
@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
@Autowired
private EmployeeRepository employeeRepository;
@PostMapping
public ResponseEntity<Employee> createEmployee(
@Valid @RequestBody Employee employee) {
Employee savedEmployee = employeeRepository.save(employee);
return new ResponseEntity<>(savedEmployee, HttpStatus.CREATED);
}
@PutMapping("/{id}")
public ResponseEntity<Employee> updateEmployee(
@PathVariable Long id,
@Valid @RequestBody Employee employee) {
Employee existingEmployee = employeeRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Employee not found with id: " + id));
existingEmployee.setFirstName(employee.getFirstName());
existingEmployee.setLastName(employee.getLastName());
existingEmployee.setEmail(employee.getEmail());
return ResponseEntity.ok(employeeRepository.save(existingEmployee));
}
}
Validating Path Variables and Query Parameters
For primitive types like path variables and request parameters, use @Validated at the class level:9
@RestController
@RequestMapping("/api/users")
@Validated // Required for parameter validation
public class UserController {
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(
@PathVariable @Min(1) Long id) {
// Implementation
}
@GetMapping("/search")
public ResponseEntity<List<User>> searchUsers(
@RequestParam @NotBlank @Size(min = 3) String name) {
// Implementation
}
}
This triggers ConstraintViolationException instead of MethodArgumentNotValidException.9
Creating Custom Error Response Structure
Define a standardized error response format:7133
public class ErrorResponse {
private int statusCode;
private Date timestamp;
private String message;
private String description;
public ErrorResponse(int statusCode, Date timestamp, String message, String description) {
this.statusCode = statusCode;
this.timestamp = timestamp;
this.message = message;
this.description = description;
}
// Getters and setters
}
For validation errors with field-level details:9
public class ValidationErrorResponse {
private List<Violation> violations = new ArrayList<>();
// Getters and setters
}
public class Violation {
private final String fieldName;
private final String message;
public Violation(String fieldName, String message) {
this.fieldName = fieldName;
this.message = message;
}
// Getters
}
Creating Custom Exceptions
Define custom exceptions for specific business scenarios:133
public class ResourceNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ResourceNotFoundException(String message) {
super(message);
}
}
public class BusinessValidationException extends RuntimeException {
public BusinessValidationException(String message) {
super(message);
}
}
Implementing Global Exception Handler
Create a centralized exception handler using @RestControllerAdvice:36713
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.Date;
@RestControllerAdvice
public class GlobalExceptionHandler {
// Handle custom ResourceNotFoundException
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleResourceNotFoundException(
ResourceNotFoundException ex, WebRequest request) {
ErrorResponse message = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
new Date(),
ex.getMessage(),
request.getDescription(false)
);
return message;
}
// Handle validation errors for @Valid on @RequestBody
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ValidationErrorResponse handleMethodArgumentNotValid(
MethodArgumentNotValidException ex) {
ValidationErrorResponse error = new ValidationErrorResponse();
for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
error.getViolations().add(
new Violation(fieldError.getField(), fieldError.getDefaultMessage())
);
}
return error;
}
// Handle validation errors for @Validated on path variables/parameters
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ValidationErrorResponse handleConstraintViolation(
ConstraintViolationException ex) {
ValidationErrorResponse error = new ValidationErrorResponse();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
error.getViolations().add(
new Violation(
violation.getPropertyPath().toString(),
violation.getMessage()
)
);
}
return error;
}
// Handle business validation exceptions
@ExceptionHandler(BusinessValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleBusinessValidationException(
BusinessValidationException ex, WebRequest request) {
return new ErrorResponse(
HttpStatus.BAD_REQUEST.value(),
new Date(),
ex.getMessage(),
request.getDescription(false)
);
}
// Handle all other exceptions
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleGlobalException(
Exception ex, WebRequest request) {
ErrorResponse message = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
new Date(),
ex.getMessage(),
request.getDescription(false)
);
return message;
}
}
Using ResponseEntityExceptionHandler
For more control, extend ResponseEntityExceptionHandler:1471
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@RestControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatusCode status,
WebRequest request) {
ValidationErrorResponse error = new ValidationErrorResponse();
ex.getBindingResult().getFieldErrors().forEach(fieldError ->
error.getViolations().add(
new Violation(fieldError.getField(), fieldError.getDefaultMessage())
)
);
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
}
@Valid vs @Validated
Understanding the difference between these annotations is crucial:101516
@Valid:
- Part of Jakarta Bean Validation (JSR 380)
- Used for triggering validation on method parameters, especially
@RequestBody - Can be used on nested objects for cascading validation
- Does not support validation groups
@Validated:
- Spring-specific annotation
- Extends
@Validfunctionality with validation groups support - Required at class level for method parameter validation (path variables, request parameters)
- Supports grouping constraints for different scenarios (create vs update)
Example with Validation Groups:159
// Define validation groups
public interface OnCreate {}
public interface OnUpdate {}
public class User {
@Null(groups = OnCreate.class)
@NotNull(groups = OnUpdate.class)
private Long id;
@NotBlank(groups = {OnCreate.class, OnUpdate.class})
private String username;
// Other fields
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ResponseEntity<User> createUser(
@Validated(OnCreate.class) @RequestBody User user) {
// Create logic
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(
@PathVariable Long id,
@Validated(OnUpdate.class) @RequestBody User user) {
// Update logic
}
}
Creating Custom Validation Annotations
For complex validation logic not covered by built-in annotations, create custom validators:1718199
Step 1: Create the Annotation:1917
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneNumberValidator.class)
@Documented
public @interface ValidPhoneNumber {
String message() default "Invalid phone number format";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Step 2: Implement the Validator:1719
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class PhoneNumberValidator implements ConstraintValidator<ValidPhoneNumber, String> {
@Override
public void initialize(ValidPhoneNumber constraintAnnotation) {
// Initialization logic if needed
}
@Override
public boolean isValid(String phoneNumber, ConstraintValidatorContext context) {
if (phoneNumber == null) {
return true; // Use @NotNull for null checks
}
// Custom validation logic
return phoneNumber.matches("^\\+?[1-9]\\d{9,14}quot;);
}
}
Step 3: Use the Custom Annotation:1917
public class ContactInfo {
@ValidPhoneNumber(message = "Phone number must be in international format")
private String phoneNumber;
// Other fields
}
Class-Level Validation for Cross-Field Dependencies:19
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordMatchesValidator.class)
public @interface PasswordMatches {
String message() default "Passwords do not match";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, UserRegistrationDto> {
@Override
public boolean isValid(UserRegistrationDto dto, ConstraintValidatorContext context) {
return dto.getPassword() != null && dto.getPassword().equals(dto.getConfirmPassword());
}
}
@PasswordMatches
public class UserRegistrationDto {
private String password;
private String confirmPassword;
// Other fields
}
Testing Validation and Exception Handling
Verify your validation and exception handling work correctly with integration tests:9
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(EmployeeController.class)
class EmployeeControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void whenInputIsInvalid_thenReturns400() throws Exception {
String invalidEmployee = "{\"firstName\":\"\",\"email\":\"invalid-email\"}";
mockMvc.perform(post("/api/employees")
.contentType(MediaType.APPLICATION_JSON)
.content(invalidEmployee))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.violations").isArray());
}
@Test
void whenResourceNotFound_thenReturns404() throws Exception {
mockMvc.perform(get("/api/employees/999"))
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.statusCode").value(404));
}
}
Best Practices
- Centralize Exception Handling: Use
@RestControllerAdviceto avoid repetitive try-catch blocks in controllers2073 - Provide Meaningful Error Messages: Include field names, validation constraints, and clear descriptions719
- Use Appropriate HTTP Status Codes: 400 for validation errors, 404 for not found, 500 for server errors37
- Validate Early: Validate input at the controller layer before processing business logic29
- Don't Expose Sensitive Information: Avoid including stack traces or internal details in production error responses17
- Return Consistent Error Structures: Define a standard error response format for all APIs73
- Use
@Validon Nested Objects: Apply@Validto nested complex types for cascading validation9 - Separate Validation from Business Logic: Keep validation constraints declarative using annotations rather than mixing with code29
By implementing these patterns, you create robust, maintainable REST APIs with comprehensive error handling and validation in Spring Boot. The combination of @RestControllerAdvice, @ExceptionHandler, and @Valid provides a powerful, declarative approach to managing exceptions and ensuring data integrity across your application.6133729
<span style="display:none">21222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293</span>
<div align="center">⁂</div>
Footnotes
-
https://www.javaguides.net/2018/09/spring-boot-crud-rest-apis-validation-example.html ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
https://howtodoinjava.com/spring-boot/spring-rest-request-validation/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
https://www.bezkoder.com/spring-boot-restcontrolleradvice/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
https://websparrow.org/spring/controlleradvice-vs-restcontrolleradvice-in-spring ↩ ↩2
-
https://bootcamptoprod.com/spring-boot-restcontrolleradvice-annotation/ ↩
-
https://www.linkedin.com/pulse/day-14-global-exception-handling-spring-boot-sanjeev-kumar-sahoo-ntmdc ↩ ↩2 ↩3
-
https://inspector.dev/spring-boot-error-handling-a-step-by-step-guide/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
https://www.geeksforgeeks.org/springboot/exception-handling-in-spring-boot/ ↩
-
https://reflectoring.io/bean-validation-with-spring-boot/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14
-
https://docs.jboss.org/hibernate/validator/6.2/reference/en-US/html_single/ ↩
-
https://jakarta.ee/learn/docs/jakartaee-tutorial/current/beanvalidation/bean-validation/bean-validation.html ↩
-
https://www.bezkoder.com/spring-boot-controlleradvice-exceptionhandler/ ↩ ↩2 ↩3 ↩4
-
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.html ↩
-
https://stackademic.com/blog/mastering-data-validation-with-valid-and-validated-annotations-in-spring-b9bb1750de25 ↩ ↩2
-
https://aboutbits.it/blog/2022-09-20-spring-boot-custom-validation-annotations ↩ ↩2 ↩3 ↩4
-
https://www.tothenew.com/blog/customizing-validation-in-spring-boot-how-to-create-your-own-constraints/ ↩
-
https://www.bezkoder.com/spring-boot-custom-validation/ ↩ ↩2 ↩3 ↩4 ↩5
-
https://howtodoinjava.com/spring-core/spring-exceptionhandler-annotation/ ↩
-
https://www.geeksforgeeks.org/springboot/request-body-and-parameter-validation-with-spring-boot/ ↩
-
https://dev.to/realnamehidden1_61/controlleradvice-and-exceptionhandler-annotations-spring-boot-15l0 ↩
-
https://github.com/juyelhushen/Spring-boot-exceptions-handling ↩
-
https://stackoverflow.com/questions/23580509/how-to-write-a-proper-global-error-handler-with-spring- mvc-spring-boot ↩
-
https://www.springboottutorial.com/spring-boot-validation-for-rest-services ↩
-
https://stackoverflow.com/questions/74605454/how-to-handle-exception-in-controller-for-spring-boot-rest-api ↩
-
https://docs.spring.io/spring-boot/reference/io/validation.html ↩
-
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc/ ↩
-
https://www.toptal.com/java/spring-boot-rest-api-error-handling ↩
-
https://mkyong.com/spring-boot/spring-rest-validation-example/ ↩
-
https://github.com/spring-projects/spring-boot/issues/40055 ↩
-
https://stackoverflow.com/questions/66371164/spring-boot-exceptionhandler-for-methodargumentnotvalidexception-in-restcontroll/74182139 ↩
-
https://stackoverflow.com/questions/36173332/difference-between-valid-and-validated-in-spring ↩
-
https://stackoverflow.com/questions/66371164/spring-boot-exceptionhandler-for-methodargumentnotvalidexception-in-restcontroll ↩
-
https://dev.to/eric6166/creating-custom-annotations-for-validation-in-spring-boot-16j1 ↩
-
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/messaging/handler/annotation/support/MethodArgumentNotValidException.html ↩
-
https://github.com/spring-projects/spring-framework/issues/31775 ↩
-
https://github.com/memosworld/spring-boot-custom-validations ↩
-
https://stackoverflow.com/questions/44051244/valid-vs-validated-in-spring-boot-rest-api-requestbody/44051634 ↩
-
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-validation.html ↩
-
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/MethodArgumentNotValidException.html ↩
-
https://www.geeksforgeeks.org/advance-java/spring-boot-custom-error-pages/ ↩
-
https://stackoverflow.com/questions/52183546/not-able-to-return-responseentity-with-exception-details-in-spring ↩
-
https://stackoverflow.com/questions/42852886/spring-4-validation-annotation-with-bindingresult-is-not-working ↩
-
https://mkyong.com/spring-boot/spring-rest-error-handling-example/ ↩
-
https://stackoverflow.com/questions/34728144/spring-boot-binding-and-validation-error-handling-in-rest-controller ↩
-
https://stackoverflow.com/questions/30917782/spring-boot-404-error-custom-error-response-rest ↩
-
https://marcdenning.com/posts/2024/02/3/validating-requests-with-spring-boot-3/ ↩
-
https://auth0.com/blog/get-started-with-custom-error-handling-in-spring-boot-java/ ↩
-
https://dev.to/noelopez/spring-rest-exception-handling-part-1-1jj2 ↩
-
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/BindingResult.html ↩
-
https://stackoverflow.com/questions/75690229/spring-boot-3-0-0-override-error-in-responseentityexceptionhandler ↩
-
https://coderanch.com/t/731375/frameworks/bindingResult-hasErrors-Spring-Boot-Thymeleaf ↩
-
https://stackoverflow.com/questions/40248640/change-spring-boots-default-json-error-response-structure ↩
-
https://springframework.guru/exception-handling-in-spring-boot-rest-api/ ↩
-
https://stackoverflow.com/questions/67454378/spring-boot-validation-with-spring-boot-starter-validation-is-not-working-for-sp ↩
-
https://central.sonatype.com/artifact/org.springframework.boot/spring-boot-starter-validation ↩
-
https://github.com/spring-projects/spring-framework/issues/34866 ↩
-
https://central.sonatype.com/artifact/org.springframework.boot/spring-boot-starter-validation/2.3.1.RELEASE ↩
-
https://docs.redhat.com/en/documentation/red_hat_jboss_enterprise_application_platform/7.3/html/development_guide/jakarta_bean_validation ↩
-
https://www.geeksforgeeks.org/java/validation-in-spring-boot/ ↩
-
https://github.com/bygui86/spring-validation/blob/master/pom.xml ↩
-
https://jakarta.ee/specifications/bean-validation/3.0/apidocs/jakarta/validation/constraints/package-summary ↩
-
https://docs.spring.io/spring-framework/reference/web/webflux/controller/ann-advice.html ↩
-
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation/3.1.0 ↩
-
https://docs.redhat.com/en/documentation/red_hat_jboss_enterprise_application_platform/7.4-beta/html/development_guide/jakarta_bean_validation ↩
-
https://tech.asimio.net/resources/code-snippets/controlleradvice-vs-restcontrolleradvice-spring-boot/ ↩
-
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation ↩
-
https://www.reddit.com/r/java/comments/fskubh/return_a_nice_response_when_validation_fails_in_a/ ↩
-
https://stackoverflow.com/questions/68993443/validation-filed-that-have-effect-on-each-other-in-spring-boot-validation ↩
-
https://www.geeksforgeeks.org/springboot/spring-boot-validation-using-hibernate-validator/ ↩
-
https://stackoverflow.com/questions/78142735/custom-error-messages-in-spring-rest-api-validation-problemdetails ↩
-
https://javanexus.com/blog/mastering-field-validation-spring-boot ↩
-
https://snyk.io/blog/guide-to-input-validation-with-spring-boot/ ↩
-
https://stackoverflow.com/questions/41481933/spring-boot-rest-validation-error-response ↩
-
https://stackoverflow.com/questions/66374404/spring-boot-how-to-validate-fields-that-depend-on-each-other ↩
-
https://www.reddit.com/r/SpringBoot/comments/172urpj/what_is_the_standardized_way_to_handle_response/ ↩
-
https://binaryscripts.com/springboot/2025/01/06/advanced-data-validation-in-spring-boot-with-custom-validators.html ↩
-
https://www.baeldung.com/exception-handling-for-rest-with-spring ↩
-
https://stackoverflow.com/questions/30431293/how-to-validate-field-level-constraint-before-class-level-constraint ↩
-
https://sudarshandoiphode.hashnode.dev/starting-with-spring-boot-starter-validations-a-simple-guide ↩
-
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-ann-rest-exceptions.html ↩