Affects: Spring Framework v5.3.14


Context

If I have an @ExceptionHandler and want to be able to perform content-type negotiation based on the incoming accept header, and what the method itself supports, I currently need to set up this logic myself, or delegate to an external non-Spring library to handle the logic.

Feature Request

Considering that ContentNegotiatingViewResolver has a good algorithm for doing this, it would be great to have this made public, or moved into a separate class to allow for easier content-negotiation where necessary.

Other information

Specific code snippets

Comment From: rstoyanchev

This is meant for use mainly with the ContentNegotiatingViewResolver where it's protected so available to sub-classes. Aside from that, we don't typically extract logic out into separate classes that don't need to be used within the framework.

I'm actually not sure how you would combine a non-Spring library with that, but if you really need to replace content negotiation with your own logic, I suggest you copy the logic that interests you, which is not that extensive and has been stable.

Comment From: jamietanna

Thanks for the reply, that makes sense as to why it's currently protected.

I've blogged about the process I followed at https://www.jvt.me/posts/2022/01/18/spring-negotiate-exception-handler/ and amended my library to allow converting between Spring and non-Spring objects for the purpose, but I think it would be beneficial to have it possible for anyone injecting/using i.e. a ContentNegotiationManager to be able to handily perform the content-negotiation instead of copy-pasting the implementation we've got in spring-web, as well as any test coverage.

Comment From: rstoyanchev

Thanks for elaborating. Given the blog post is about @ExceptionHandler methods with ResponseEntity, I think there is some confusion as ContentNegotiatingViewResolver plays no role for that case. Such methods are for REST clients where the returned object is written to the response body while a ViewResolver is for HTML clients and it's about selecting a View to render the response with.

I don't think extracting the content negotiation as a separate class is as simple as what you see in ContentNegotiatingViewResolver and I don't think it makes sense to expect applications to do their own content negotiation, which is what such an abstraction would suggest. Of course you're free to do so, but I would rather discuss the actual problems this aims to solve.

I think content negotiation for error responses is distinct from content negotiation for successful responses. We can't assume that whatever the handler methods produce (json vs text in your example) is also what error handlers should, considering also that handler methods could be producing any media type really, including binary. This is where a client might add "application/problem+json" to the Accept header, but in the absence of that an application might use a fixed, uniform format across all error responses.

Comment From: jamietanna

Thanks, that makes sense why we can't reuse it.

I've wrapped this into a library until it's decided that we may want to provide a means to do this that is built into Spring, which I still hope we can do in the future.