Browse Source

Relax media type checks in HttpMessageConverters

Prior to this commit, `HttpMessageConverters` would assert that the
given converter in `withXmlConverter` has a media type that is equal to
"application/xml" in its list of supported converters.

This approach would not work if the given converter supports
"application/xml;charset=UTF-8" because of the strict equal check being
performed.

This commit ensures that we only consider the type and subtype of the
considered media types when comparing, removing the parameters from the
picture.

Fixes gh-35801
pull/35808/head
Brian Clozel 1 month ago
parent
commit
3ac7f83900
  1. 27
      spring-web/src/main/java/org/springframework/http/converter/DefaultHttpMessageConverters.java
  2. 17
      spring-web/src/test/java/org/springframework/http/converter/DefaultHttpMessageConvertersTests.java

27
spring-web/src/main/java/org/springframework/http/converter/DefaultHttpMessageConverters.java

@ -162,8 +162,7 @@ class DefaultHttpMessageConverters implements HttpMessageConverters { @@ -162,8 +162,7 @@ class DefaultHttpMessageConverters implements HttpMessageConverters {
void setStringConverter(HttpMessageConverter<?> stringConverter) {
Assert.isTrue(stringConverter.getSupportedMediaTypes().contains(MediaType.TEXT_PLAIN),
"stringConverter should support 'text/plain'");
checkConverterSupports(stringConverter, MediaType.TEXT_PLAIN);
this.stringConverter = stringConverter;
}
@ -173,20 +172,17 @@ class DefaultHttpMessageConverters implements HttpMessageConverters { @@ -173,20 +172,17 @@ class DefaultHttpMessageConverters implements HttpMessageConverters {
}
void setJsonConverter(HttpMessageConverter<?> jsonConverter) {
Assert.isTrue(jsonConverter.getSupportedMediaTypes().contains(MediaType.APPLICATION_JSON),
"jsonConverter should support 'application/json'");
checkConverterSupports(jsonConverter, MediaType.APPLICATION_JSON);
this.jsonConverter = jsonConverter;
}
void setXmlConverter(HttpMessageConverter<?> xmlConverter) {
Assert.isTrue(xmlConverter.getSupportedMediaTypes().contains(MediaType.TEXT_XML),
"xmlConverter should support 'text/xml'");
checkConverterSupports(xmlConverter, MediaType.TEXT_XML);
this.xmlConverter = xmlConverter;
}
void setSmileConverter(HttpMessageConverter<?> smileConverter) {
Assert.isTrue(smileConverter.getSupportedMediaTypes().contains(new MediaType("application", "x-jackson-smile")),
"smileConverter should support 'application/x-jackson-smile'");
checkConverterSupports(smileConverter, new MediaType("application", "x-jackson-smile"));
this.smileConverter = smileConverter;
}
@ -196,17 +192,24 @@ class DefaultHttpMessageConverters implements HttpMessageConverters { @@ -196,17 +192,24 @@ class DefaultHttpMessageConverters implements HttpMessageConverters {
}
void setCborConverter(HttpMessageConverter<?> cborConverter) {
Assert.isTrue(cborConverter.getSupportedMediaTypes().contains(MediaType.APPLICATION_CBOR),
"cborConverter should support 'application/cbor'");
checkConverterSupports(cborConverter, MediaType.APPLICATION_CBOR);
this.cborConverter = cborConverter;
}
void setYamlConverter(HttpMessageConverter<?> yamlConverter) {
Assert.isTrue(yamlConverter.getSupportedMediaTypes().contains(MediaType.APPLICATION_YAML),
"yamlConverter should support 'application/yaml'");
checkConverterSupports(yamlConverter, MediaType.APPLICATION_YAML);
this.yamlConverter = yamlConverter;
}
private void checkConverterSupports(HttpMessageConverter<?> converter, MediaType mediaType) {
for (MediaType supportedMediaType : converter.getSupportedMediaTypes()) {
if (mediaType.equalsTypeAndSubtype(supportedMediaType)) {
return;
}
}
throw new IllegalArgumentException("converter should support '" + mediaType + "'");
}
void addCustomMessageConverter(HttpMessageConverter<?> customConverter) {
Assert.notNull(customConverter, "'customConverter' must not be null");
this.customConverters.add(customConverter);

17
spring-web/src/test/java/org/springframework/http/converter/DefaultHttpMessageConvertersTests.java

@ -65,42 +65,47 @@ class DefaultHttpMessageConvertersTests { @@ -65,42 +65,47 @@ class DefaultHttpMessageConvertersTests {
void failsWhenStringConverterDoesNotSupportMediaType() {
assertThatIllegalArgumentException()
.isThrownBy(() -> HttpMessageConverters.forClient().withStringConverter(new CustomHttpMessageConverter()).build())
.withMessage("stringConverter should support 'text/plain'");
.withMessage("converter should support 'text/plain'");
}
@Test
void failsWhenJsonConverterDoesNotSupportMediaType() {
assertThatIllegalArgumentException()
.isThrownBy(() -> HttpMessageConverters.forClient().withJsonConverter(new CustomHttpMessageConverter()).build())
.withMessage("jsonConverter should support 'application/json'");
.withMessage("converter should support 'application/json'");
}
@Test
void canConfigureXmlConverterWithCharset() {
HttpMessageConverters.forClient().withXmlConverter(new JacksonXmlHttpMessageConverter()).build();
}
@Test
void failsWhenXmlConverterDoesNotSupportMediaType() {
assertThatIllegalArgumentException()
.isThrownBy(() -> HttpMessageConverters.forClient().withXmlConverter(new CustomHttpMessageConverter()).build())
.withMessage("xmlConverter should support 'text/xml'");
.withMessage("converter should support 'text/xml'");
}
@Test
void failsWhenSmileConverterDoesNotSupportMediaType() {
assertThatIllegalArgumentException()
.isThrownBy(() -> HttpMessageConverters.forClient().withSmileConverter(new CustomHttpMessageConverter()).build())
.withMessage("smileConverter should support 'application/x-jackson-smile'");
.withMessage("converter should support 'application/x-jackson-smile'");
}
@Test
void failsWhenCborConverterDoesNotSupportMediaType() {
assertThatIllegalArgumentException()
.isThrownBy(() -> HttpMessageConverters.forClient().withCborConverter(new CustomHttpMessageConverter()).build())
.withMessage("cborConverter should support 'application/cbor'");
.withMessage("converter should support 'application/cbor'");
}
@Test
void failsWhenYamlConverterDoesNotSupportMediaType() {
assertThatIllegalArgumentException()
.isThrownBy(() -> HttpMessageConverters.forClient().withYamlConverter(new CustomHttpMessageConverter()).build())
.withMessage("yamlConverter should support 'application/yaml'");
.withMessage("converter should support 'application/yaml'");
}

Loading…
Cancel
Save