Affects: 5.2.10.RELEASE and later
The AbstractJackson2HttpMessageConverter.writeInteral method was modified to use a try with resources block to optimize Jackson resource management gh-25910. This now calls close on the JsonGenerator in the event of an error such as a JsonProcessingException, which flushes what was written before the error occurred to the response body. When attempting to return a customized error response from a ControllerAdvice, the response body will contain the data written before the exception was thrown concatenated with the data written by the ControllerAdvice. This leads to an invalid response being returned to the client.
Comment From: spring-projects-issues
Fixed via a8091b916b74dec5da5464c0b373939b727c8924
Comment From: bclozel
Thanks for this report @jdelong747 !
We've reverted this behavior change with a8091b9.
There are still a few things to consider here. The fact that the JSON payload might not be written to the response output in case of serialization errors is not a feature: this is really about the fact that the underlying buffer is not full yet or that Jackson didn't decide to flush it at that point. This is really accidental. The best way to realize that is that you could configure Jackson to flush after each write, or just writing a large body could flush to the output before the error happens. In your case, the response body might be small enough that you're relying on this behavior.
In general, you should not rely on an @ExceptionHandler
to handle an exception that happens while writing to the response. At that point, there's no guarantee that the HTTP response has not been committed and bits sent over the network.
Note that we won't be merging forward this commit, as:
- this behavior is not an actual feature and is not 100% controlled
- this behavior is not consistent with the WebFlux and Messaging codecs, which are flushing or closing the generator
- not closing the generator for error cases prevents resources from being recycled as expected by Jackson
I'm afraid I don't see a way to reproduce this former behavior on your side in Framework 5.3, besides getting full control and serializing to some ByteArrayOutputStream
and flushing that to the response later. This comes with performance and memory downsides, as you would expect.
We've added a note in the migration wiki in the MVC section of the 5.3 migration guide.