Spring Controller doesn't apply Accept mediatype

51 Views Asked by At

Not a trivial task I have. Very legacy project (Spring 4.3, xml-configuration, web.xml, etc) There was Spring Controller which produce only one mediatype (application/xml). Customer decided that he needs also application/json. No question, some refactoring, adding necessary annotation and magic works. To configuration was added instruction to use by default application/xml. All tested locally, all works. Problem - customer has an old apps, which use org.springframework.web.client.RestTemplate, and uses it without any headers. Surprise! RestTemplate with empty headers, adds default the headers before send the request. Endpoint receives the httprequest with header Accept="application/octet-stream, application/json, application/*+json, /". Customer receives the object in json (but waiting for xml). Decision - not so good, but as is - add filter which will check header for Accept and if it contains more then one mediatype, replace it to application/xml. Filter does work fine, all needed headers replace. Debugger shows that Controller receive already new headers, but still keep going to return application/json in response body. What's wrong?

config.xml

...
    <bean id="mvcContentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="favorParameter" value="true"/>
        <property name="mediaTypes">
            <value>
                xml=application/xml
                json=application/json
            </value>
        </property>
        <property name="defaultContentType" value="application/xml"/>
    </bean>
...

web.xml

...
    <filter>
        <filter-name>acceptFilter</filter-name>
        <filter-class>la.la.AcceptFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>acceptFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
...

AcceptFilter.java

...
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;

        String accept = req.getHeader("Accept");
        if (accept.split(",").length > 1) {
            MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(req);
            mutableRequest.putHeader("accept", "application/xml");
            mutableRequest.putHeader("Content-Type", "application/xml");
            ((HttpServletResponse) servletResponse).setHeader("Accept", "application/xml");
            ((HttpServletResponse) servletResponse).setHeader("Content-Type", "application/xml");
            servletResponse.setContentType("application/xml");
            filterChain.doFilter(mutableRequest, servletResponse);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    final class MutableHttpServletRequest extends HttpServletRequestWrapper {
...

LaLaController.java

...
    @RestController
    @RequestMapping(value = CONTROLLER_PATH,
        produces = {APPLICATION_XML_VALUE, APPLICATION_JSON_VALUE})
    public class LaLaController {

        @GetMapping("/firstEndpoint")
        public JustObject firstEndpoint() {
            return new JustObject("some information", "some details");
        }

...

Example request:

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<byte[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, byte[].class);
    byte[] body = responseEntity.getBody();

I tried interceptor, but there also no way to change header. I have no ideas. If set Accept in request - all works fine. I will appreciate if someone give me better decision for my issue.

0

There are 0 best solutions below