Spring-cloud-contract: Content Type being append with charset=ISO-8859-1

Created on 15 Jun 2020  路  13Comments  路  Source: spring-cloud/spring-cloud-contract

Hello!

I'm updating a Spring Boot 2.2 app with Spring Cloud Hoxton.SR1 to Spring Boot 2.3 with Hoxton.SR5, and the provider tests started to fail. The test fail with the following message:

DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=ISO-8859-1' not supported]

Something is appending the charset=ISO-8859-1 to the Content-Type header, even tho our contract DSL sets it to application/json only:

Contract.make {
    description 'create something'
    request {
        method POST()
        url '/something'
        body(
            property: 'value'
        )
        headers {
            contentType(applicationJson()) // This is "application/json"
        }
    }
    response {
        status OK()
    }
}

I think UTF-8 is the default for Spring Boot 2.2 onward, so it was not necessary anymore to use applicationJsonUtf8() as content type. If I do change the content type to applicationJsonUtf8(), then that charset=ISO-8859-1 is not appended and the test pass.

Is appending a default charset an expected behavior for Spring Cloud Contract?

Best regards,
Rafael Pacheco.

documentation first-timers-only gracehopperOSD help wanted

Most helpful comment

Hi all,
I had a simial issue, here my investigations:
Spring Boot 2.3 uses Spring-web 5.2.7, (Spring Boot 2.2 used Spring-Web 5.2.6)
Spring-web v.5.2.7 has a class AbstractJackson2HttpMessageConverter and it was modified - it started to check encoding for Json body (canRead(@Nullable MediaType mediaType)), so now only null encodign or UTF-xx supported.

On other hand RestAssured (3.3 in my case) by default uses ISO_8859_1 as defaultContentCharset (see deafult constructor of RestAssuredMockMvcConfig -> new EncoderConfig()) and if you don't specify any charset excplisitly in the request content-type - it will add the defalt one.

So Spring Boot 2.3 (Spring Web 5.2.7) becomes more strict to headers.

My solution was to bring custom configuration to RestAssured:
RestAssuredMockMvc.config = new RestAssuredMockMvcConfig() .encoderConfig(new EncoderConfig(UTF_8.name(), UTF_8.name()));

or opt-out appending of default content charset:
EncoderConfig encoderConfig = new EncoderConfig() .appendDefaultContentCharsetToContentTypeIfUndefined(false); RestAssuredMockMvcConfig restAssuredConf = new RestAssuredMockMvcConfig() .encoderConfig(encoderConfig); RestAssuredMockMvc.config = restAssuredConf;

All 13 comments

I've created a sample repo for this issue:

https://github.com/bidadh/scc-content-type-issue

Also seeing this issue

Hi all,
I had a simial issue, here my investigations:
Spring Boot 2.3 uses Spring-web 5.2.7, (Spring Boot 2.2 used Spring-Web 5.2.6)
Spring-web v.5.2.7 has a class AbstractJackson2HttpMessageConverter and it was modified - it started to check encoding for Json body (canRead(@Nullable MediaType mediaType)), so now only null encodign or UTF-xx supported.

On other hand RestAssured (3.3 in my case) by default uses ISO_8859_1 as defaultContentCharset (see deafult constructor of RestAssuredMockMvcConfig -> new EncoderConfig()) and if you don't specify any charset excplisitly in the request content-type - it will add the defalt one.

So Spring Boot 2.3 (Spring Web 5.2.7) becomes more strict to headers.

My solution was to bring custom configuration to RestAssured:
RestAssuredMockMvc.config = new RestAssuredMockMvcConfig() .encoderConfig(new EncoderConfig(UTF_8.name(), UTF_8.name()));

or opt-out appending of default content charset:
EncoderConfig encoderConfig = new EncoderConfig() .appendDefaultContentCharsetToContentTypeIfUndefined(false); RestAssuredMockMvcConfig restAssuredConf = new RestAssuredMockMvcConfig() .encoderConfig(encoderConfig); RestAssuredMockMvc.config = restAssuredConf;

Hi all,
...
My solution was to bring custom configuration to RestAssured:
RestAssuredMockMvc.config = new RestAssuredMockMvcConfig() .encoderConfig(new EncoderConfig(UTF_8.name(), UTF_8.name()));

I have this exact issue in my MockMvC mockHttRequests (unit tests):

  mockMvc.perform(MockMvcRequestBuilders.post(ENUM_BODY_ENDPOINT)
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"testEnum\": \"CODE_A  \"}"))
                .andExpect(status().isBadRequest());

Suddenly gave the error "http 415: application/json;charset_ISO_8859_1" is not supported. I fixed the unit test by changing the MediaType:

  mockMvc.perform(MockMvcRequestBuilders.post(ENUM_BODY_ENDPOINT)
                .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
                .content("{\"testEnum\": \"CODE_A  \"}"))
                .andExpect(status().isBadRequest());

But this media type is deprecated. Could you guide me towards how can I can configure for MockMvc what you did for RestAssured?

Hi! There was a small bug https://github.com/rest-assured/rest-assured/pull/1341 in Rest Assured lib that was appending charset=ISO-8859-1 instead of using charset=UTF-8 as default for content type application/json. I've fixed it, maintainer merged and created release 4.3.1 (2020-07-03). Updating artifact is fixing this issue for me.
Pls feel free to try and share your thoughts. Thanks.

Since Spring Boot is using 3.3.0 version of rest assured I asked for applying the fix in 3.3.x branch.

Just FYI Spring removed the charset parameter completely https://github.com/spring-projects/spring-framework/issues/22788 since https://tools.ietf.org/html/rfc7159#section-11 does not define any parameters for application/json.

Indeed until Boot bumps Rest Assured to 4.x I guess we need to do

        EncoderConfig encoderConfig = new EncoderConfig().appendDefaultContentCharsetToContentTypeIfUndefined(false);
        RestAssuredMockMvc.config = new RestAssuredMockMvcConfig().encoderConfig(encoderConfig);

Maybe we should add this as the documentation entry until this https://github.com/spring-projects/spring-boot/issues/22303 issue gets resolved...

@MaciejZiarko this seems to give us the same effect.
java.lang.IllegalStateException: You haven't configured a MockMVC instance. You can do this statically

@marcingrzejszczak
java.lang.IllegalStateException: You haven't configured a MockMVC instance. You can do this statically Still occurs. Also we have noticed the github examples have the only structure not the new structure with package contractTest. Is there a working example of this?

java.lang.IllegalStateException: You haven't configured a MockMVC instance. You can do this statically Still occurs

Most likely you're generating tests in JUnit 5 and have the JUnit 4 before section which is not executed.

Is there a working example of this?

https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/producer_with_latest_3_0_features_gradle/src/contractTest

This got fixed https://github.com/spring-projects/spring-boot/issues/22303 so I guess we can close this issue

Was this page helpful?
0 / 5 - 0 ratings