4

I have a rest api written in Java (spring boot), my request takes a json string from request header(do not ask why this way:), e.g. {flowerId: 123} In my controller, I map the string to object. So when users pass in junk data, e.g. {flowerId: abc}, JsonMappingException will be thrown. I'd like to handle the exception in my exception handler but unable to catch it in my handler. Did I miss something? thanks

See my code below.

   @RestController
    public class FlowerController  {
       @GetMapping
        @ResponseStatus(HttpStatus.OK)
        public GetFlowerResponse getFlowers(@RequestHeader(name = Constants.myHeader) String flowerIdString) throws IOException {
            GetFlowerRequest getFlowerRequest = new ObjectMapper().readValue(flowerIdString, GetFlowerRequest.class);
            //get Flower info with request ...
        }
    }


    @RestControllerAdvice
    public class ApplicationExceptionHandler {
        @ExceptionHandler(value = {JsonMappingException.class})
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public GetFlowerResponse processServletRequestBindingException(HttpServletRequest req, ServletRequestBindingException e) {
            return buildExceptionResponse(e, ErrorMessages.INVALID_REQUEST.getCode(), e.getMessage());
        }

        @ExceptionHandler(value = Exception.class)
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        public GetFlowerResponse processUnhandledExceptions(HttpServletRequest req, Exception e) {
            return buildExceptionResponse(e, ErrorMessages.SERVICE_UNAVAILABLE.getCode(), ErrorMessages.SERVICE_UNAVAILABLE.getDescription());
        }
    }   

    public class GetFlowerRequest {
        int flowerId;
    }

public class GetFlowerResponse {
    private List<ReturnDetail> returnDetails;
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public class ReturnDetail {
    @Builder.Default
    private Integer code = 0;

    @Builder.Default
    private String message = "";

    private String source;
toosensitive
  • 2,335
  • 7
  • 46
  • 88
  • i'm not seeing anything wrong in your code, can you update the error response, and make sure spring scans `Handler` class and create bean – Ryuzaki L Dec 06 '18 at 23:44
  • If the format of the JSON is not correct a `JsonParseException` exception will be raised. If the format of the JSON is correct, but the inputs are not valid (example: String is passed where integer is expected), then `JsonMappingException` is usually raised. Probably you should catch `JsonParseException` as well. – Ervin Szilagyi Dec 06 '18 at 23:55
  • thanks, response updated – toosensitive Dec 11 '18 at 23:31

1 Answers1

0

Your exception handler is invalid. Your method processServletRequestBindingException() declares ServletRequestBindingException exception as parameter but is annotated for @ExceptionHandler(value = {JsonMappingException.class}). This exception types must be compatible, otherwise it won't work and you will get an exception during exception handling.

new ObjectMapper().readValue() throws both JsonParseException and JsonMappingException. Both extend JsonProcessingException so you most likely need a handler for this exception to cover both cases:

@ExceptionHandler(JsonProcessingException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public GetFlowerResponse handleJsonProcessingException(
        HttpServletRequest req, JsonProcessingException ex) {
   ...
}

Do note that it's preferable to autowire ObjectMapper from the Spring context and don't create a new instance.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
  • But my doubt at least it should go to exception method right – Ryuzaki L Dec 12 '18 at 00:08
  • 1
    @Karol Dowbecki, I tried with your advise i.e. adding another method handleJsonProcessingException, still not working, not able to catch. and not even be caught in processUnhandledExceptions either – toosensitive Dec 12 '18 at 17:32
  • @toosensitive you also must remove existing handler for `JsonMappingException` for this to work as `JsonProcessingException` is more generic. Possibly your `@RestControllerAdvice` is not registered by Spring but there is no way to tell from your small example. – Karol Dowbecki Dec 12 '18 at 17:44