-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Description
Tim Reidel opened SPR-9159 and commented
An IOException is thrown by Jetty when returning an object from an exception handler in my @Controller
annotated class. Some investigation revealed that the issue was seen only when I defined an error response in the @ResponseStatus
annotation.
An example @ExceptionHandler
that demonstrates the issue:
@ExceptionHandler(TestException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "test error")
public @ResponseBody
TestObject handleTestException(TestException e)
{
return new TestObject(e.getMessage());
}
It seems the IOException is triggered by the HTTPConnection being written to twice in ServletInvocableHandlerMethod.invokeAndHandle()
- in the call to setResponseStatus() in ServletInvocableHandlerMethod.invokeAndHandle()
- in the call to returnValueHandlers.handleReturnValue()
If there is a reason defined in the @ResponseStatus
then setResponseStatus() will write output text to the HTTP response which will cause the outputStream to close. Later within returnValueHandlers.handleReturnValue() the JAXB seralization attempts to write to the outputStream which is closed. This triggers the IOException.
Below is a snippet from ServletInvocableHandlerMethod that shows the logic that generates the error page via sendError(). This is only called when this.responseReason is non-null. Thus if you define a reason in the @ResponseStatus
annotation the @ResponseBody
annotation won't work.
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
if (this.responseStatus != null) {
if (StringUtils.hasText(this.responseReason)) {
webRequest.getResponse().sendError(this.responseStatus.value(), this.responseReason);
}
else {
webRequest.getResponse().setStatus(this.responseStatus.value());
}
// to be picked up by the RedirectView
webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, this.responseStatus);
}
}
Affects: 3.1.1