javaspring-bootspring-mvcexceptioncontroller-advice

How to throw NoHandlerFoundException if path param is not Long in springboot


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);
        }
    
    }