Issue
Currently, there is a GetMapping like follows
@GetMapping(value = "/{id}")
public ResponseEntity<Dog> getTrainById(@PathVariable Long id) {
Dog dog= animalService.getAnimalById(id);
return new ResponseEntity<>(Dog , HttpStatus.OK);
}
now if someone accesses http://localhost:8080/api/animal/1, it returns the animal.
But I need to throw NoHandlerFoundException if someone accesses this endpoint without a Long variable as a path parameter, that means like this http://localhost:8080/api/animal/asdsad
IF anyone can tell me way to achieve this, that would be much appreciated
Also I have global exception handling like follows
@ControllerAdvice
public class DemoExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<GenericResponse> customHandleNotFound(Exception ex, WebRequest request)
{
return new ResponseEntity<>(new GenericResponse(ex.getMessage(), null), HttpStatus.NOT_FOUND);
}
@Override
protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return new ResponseEntity<>(new GenericResponse("invalid endpoint", null), HttpStatus.METHOD_NOT_ALLOWED);
}
}
Solution
In this case which the request cannot be resolved to the parameter type of a controller method , it will throw MethodArgumentTypeMismatchException
.
So the most effective way to solve the problem is to think about how to handle MethodArgumentTypeMismatchException
directly but not think how to make it re-throw NoHandlerFoundException
. So you can simply create a @ControllerAdvice
to handle MethodArgumentTypeMismatchException
:
@ControllerAdvice
public class DemoExceptionHandler {
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<Object> handle(MethodArgumentTypeMismatchException ex) {
return new ResponseEntity<>( GenericResponse("invalid endpoint", null), HttpStatus.METHOD_NOT_ALLOWED);
}
}
It will be applied to all controllers that throw this type of exception . If you only want it to apply for a particular controller but not globally , you can do :
@RestController
@RequestMapping("/foo")
public class FooController {
@GetMapping(value = "/{id}")
public ResponseEntity<Dog> getTrainById(@PathVariable Long id) {
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<Object> handleMethodArgumentTypeMismatchException() {
return new ResponseEntity<>( GenericResponse("invalid endpoint", null), HttpStatus.METHOD_NOT_ALLOWED);
}
}
Answered By - Ken Chan
Answer Checked By - Senaida (JavaFixing Volunteer)