Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.bind.MethodArgumentNotValidException]
Springs ResponseEntityExceptionHandler has a method handleException which is annotated with :
@ExceptionHandler({
...
MethodArgumentNotValidException.class,
...
})
Your method handleMethodArgumentNotValidException is also annotated to handle MethodArgumentNotValidException. So spring finds two methods that should be used to handle the same exception, that is the reason for the exception.
**Solution ** Do not add a new method handleMethodArgumentNotValidException instead just override the method ResponseEntityExceptionHandler.handleMethodArgumentNotValid , and do not annotate it. Your class ErrorWrapper must extend ResponseEntity for that.
Try to override the method handleMethodArgumentNotValid, In my case the method become like this:
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status,
WebRequest request) {
String errorMessage = ex.getBindingResult().getFieldErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.findFirst()
.orElse(ex.getMessage());
return response(ex, request, HttpStatus.BAD_REQUEST, errorMessage);
}
private ResponseEntity<Object> response(Exception ex, WebRequest request, HttpStatus status,
String message) {
return handleExceptionInternal(ex, message, header(), status, request);
}
Handel Exception
@ControllerAdvice
@RestController
@Slf4j
public class ExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
List<String> errorList = ex
.getBindingResult()
.getFieldErrors()
.stream()
.map(fieldError -> fieldError.getDefaultMessage())
.collect(Collectors.toList());
ErrorDetails errorDetails = new ErrorDetails(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errorList);
return handleExceptionInternal(ex, errorDetails, headers, errorDetails.getStatus(), request);
}
}
}
Customize Error Message
@Data
public class ErrorDetails {
private HttpStatus status;
private String message;
private List<String> errors;
public ErrorDetails(HttpStatus status, String message, List<String> errors) {
super();
this.status = status;
this.message = message;
this.errors = errors;
}
public ErrorDetails(HttpStatus status, String message, String error) {
super();
this.status = status;
this.message = message;
errors = Arrays.asList(error);
}
}
Sample Response
{
"status": "BAD_REQUEST",
"message": "Validation failed for argument [0] in public void com.ns.hospitalmanagement.resource.PatientResource.createPatient(com.ns.hospitalmanagement.entity.Patient) with 2 errors: [Field error in object 'patient' on field 'name': rejected value [null]; codes [NotNull.patient.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [patient.name,name]; arguments []; default message [name]]; default message [Name Can not be Null]] [Field error in object 'patient' on field 'name': rejected value [null]; codes [NotEmpty.patient.name,NotEmpty.name,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [patient.name,name]; arguments []; default message [name]]; default message [Name Can not be Empty]] ",
"errors": [
"Name Can not be Null",
"Name Can not be Empty"
]
}