Reputation: 471
I'm using @ControllerAdvice to detect exceptions that are thrown in the application.
Trying to throw exception during creation of a class:
public void setStatus(String status) throws InvalidInputStatusException{
if(checkIfStatusIsAllowed(status)) {
this.status = status;
} else {
throw new InvalidInputStatusException();
}
}
Trying to catch the error:
@ControllerAdvice
public class RekvisisjonRESTControllerExceptionHandler {
//TODO: Add logger here!
@ExceptionHandler
public final ResponseEntity<RekvisisjonRESTErrorResponse> handleException(InvalidInputStatusException e, WebRequest request) {
//TODO: Do some logging
return new ResponseEntity<>(new RekvisisjonRESTErrorResponse(HttpStatus.BAD_REQUEST.toString(),
e.getClass().getName(),
e.getMessage(), LocalDateTime.now()), HttpStatus.BAD_REQUEST);
}
}
What I want is the object specified above returned, but I get this crap here instead:
"error": "Bad Request",
"message": "JSON parse error: Ugyldig status som input; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Ugyldig status som input\n at [Source: (PushbackInputStream); line: 2, column: 12] (through reference chain: no.pasientreiser.atom.rekvisisjon.controller.dto.UpdateRekvisisjonStatusRequest[\"status\"])",
"trace": "org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Ugyldig status som input; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Ugyldig status som input\n at [Source: (PushbackInputStream); line: 2, column: 12] (through reference chain: no.pasientreiser.atom.rekvisisjon.controller.dto.UpdateRekvisisjonStatusRequest[\"status\"])\n\tat org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:245)\n\tat org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:227)\n\tat org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:205)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:158)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:131)\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)\n\tat org.springframework.web.me
I'm assuming it fails to detect the intended exception because another is thrown before it, but this is not what i want.
Any recommendations?
Upvotes: 1
Views: 184
Reputation: 1303
An exception handler handles exceptions that occur in your handler methods (see https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc). The exception you see happens earlier, while Spring is trying to turn the JSON request body into an UpdateRekvisisjonStatusRequest
. The Jackson JSON deserializer is invoking the setStatus
method and encounters an exception, which Spring takes to mean the HTTP body is not readable (since Jackson couldn't deserialize it).
Take a look at how Spring MVC handles validation instead: https://spring.io/guides/gs/validating-form-input/
Upvotes: 2
Reputation: 2027
First your RekvisisjonRESTControllerExceptionHandler should extends from ResponseEntityExceptionHandler. If you return ResponseEntity, it would wrap your value class (RekvisisjonRESTErrorResponse). Here your exception is generated after the advice, when json serialized.
Upvotes: 0
Reputation: 7810
The exception happens not in your business code, but during the parsing of the request into your request presentation object. Spring Web treats any kind of exception that happened during parsing of the request as a presentation-level error, not a business-level error, hence, your exception handler doesn't get invoked.
Since you try to enforce a business rule here, I'd propose to move it out of the setter method of a presentation object and find a better place for it. E.g. put this logic inside the business entity, or one of your services, or at the very least in the controller method that accepts the request.
Upvotes: 0