Spring Boot version 2.4.0 Also testing in spring boot 1.3.2.RELEASE When the default content type is set to XML if a request comes in that allows a "*/*" response then a JSON response is returned.

Clarification - A header that allows a "*/*" response. For example "Accept: text/html, */*" but not the wildcard header itself, "Accept:*/*". Note that this sentence wasn't in the initial ticket.

Workaround: Add in a Jaxb2CollectionHttpMessageConverter and a Jaxb2RootElementHttpMessageConverter as the first convertors.

Problems with the workaround. This is undocumented behaviour checking the documentation of https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.html#extendMessageConverters-java.util.List- It doesn't say that the order of the convertors matter.

Either this should be documented "Order of HttpConverters matters" or there should be a different resolution strategy.

Therefore I'm concerned that the workaround may be less than stable.

It would be good to have an explicit favoured response type that is returned when there are equal priorities in content negotiation strategies.

A full application that uses this is posted to a related stackoverflow ticket https://stackoverflow.com/questions/65689179/how-do-you-configure-spring-boot-2-to-return-xml-by-default/65702088#65702088

I can send the file if required. Or zip up a project.

Comment From: wilkinsona

As you've learned, the ordering of HTTP message converters is important. The first converter in the list that's capable of writing a response in an acceptable format is used. We'll transfer this issue to the Spring Framework team so that they can consider some updates to the documentation/javadoc to make this clearer.

Comment From: rstoyanchev

When the default content type is set to XML if a request comes in that allows a "/" response then a JSON response is returned.

I am not able to reproduce that, meaning that I did not have to configure JAXB ahead of other converters. Simply setting the default content type:

@Configuration
public static class ServerConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_XML);
    }
}

is sufficient to enforce XML by default:

$ curl -v -H "Accept:*/*" http://localhost:8080/xml-test
*   Trying 127.0.0.1:8080...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /xml-test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.68.0
> Accept:*/*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 
< Content-Type: application/xml
< Transfer-Encoding: chunked
< Date: Fri, 15 Jan 2021 18:04:55 GMT
< 
* Connection #0 to host localhost left intact
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><person><firstName>Jon</firstName><lastName>Doe</lastName></person>

And if the above configuration is removed then:

$ curl -v -H "Accept:*/*" http://localhost:8080/xml-test
*   Trying 127.0.0.1:8080...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /xml-test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.68.0
> Accept:*/*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Fri, 15 Jan 2021 18:10:16 GMT
< 
* Connection #0 to host localhost left intact
{"firstName":"Jon","lastName":"Doe"}

So this is expected behavior and it makes sense that if the client accepts anything, something is going to have to be chosen first by default. Nevertheless you can choose a default media type on the server side.

Comment From: Athas1980

@rstoyanchev I appologise what I stated above is incorrect. The media type "*/*" does indeed return the XML as requested.

My actual testing was actually with some other headers which are based on a client we have. (I think that its the default headers for a HttpUrlConnection)

Curl request I was making during my tests

$ curl localhost:8080 -H"Accept: text/html, image/gif, image/jpg;q=0.2, */*;q=0.2"  
{"firstName":"Jon","lastName":"Doe"}%

Curl request I made based on what you posted.

``` ➜ $ curl localhost:8080 -H"Accept: /"

JonDoe% ```

You are correct that the wildcard mime type falls back on default. However this is inconsistent with the above mime type that is equally applicable to XML and JSON. I would have expected the behaviour to be if the default mime type is fufillable by the accept header and it has the same quality as the provided mime type. Then fall back on the default.

Taking these two requests in my opinion it violates the law of least surprise that accepting "text/html" changes the response body. The text/html should be irrelevant unless HTML is being returned.

$ curl localhost:8080 -H"Accept: text/html, */*"  
{"firstName":"Jon","lastName":"Doe"}%

$ curl localhost:8080 -H"Accept:*/*"              
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><person><firstName>Jon</firstName><lastName>Doe</lastName></person>%

Comment From: rstoyanchev

I see yes the order is significant. We can do some update to the documentation. It is a little more nuanced than that since we go through the Accept-able media types, in order, and check against every supported (i.e. producible) media type. So the order of both Accept-able and producible media types is important, and so is the presence of wildcards and qualifiers.

Comment From: Athas1980

I realised it was more nuanced as I stepped through the code that was choosing the output this is why I realised that the registering of the converters mattered.

Theres a method I can't find right now that sorts media types by quality and by specificity. Law of least supprise would be sorting by quality, specificity, isDefault i.e. take default into consideration when sorting the media types, however I'd be reluctant to request that as a change as I think it may break backwards compatibility for people in the opposite situation than I am in. I.e. people who depend on the current behaviour.