Improve ResourceHttpMessageConverter target type support

This commit updates the target type detection in
`ResourceHttpMessageConverter` to only support target types that are
relevant: `InputStreamResource` for streaming, and types assignable from
`ByteArrayResource` for non-streaming cases.

Closes gh-36368
This commit is contained in:
Brian Clozel
2026-02-23 11:02:22 +01:00
parent 53f1656f56
commit 7299ff9326
2 changed files with 43 additions and 3 deletions
@@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.core.io.Resource;
import org.springframework.http.ContentDisposition;
import org.springframework.http.MediaType;
@@ -41,6 +42,7 @@ import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ResourceHttpMessageConverter}.
* @author Arjen Poutsma
* @author Kazuki Shimizu
* @author Brian Clozel
@@ -52,13 +54,15 @@ class ResourceHttpMessageConverterTests {
@Test
void canReadResource() {
assertThat(converter.canRead(Resource.class, new MediaType("application", "octet-stream"))).isTrue();
assertThat(converter.canRead(Resource.class, MediaType.APPLICATION_OCTET_STREAM)).isTrue();
assertThat(converter.canRead(ByteArrayResource.class, MediaType.APPLICATION_OCTET_STREAM)).isTrue();
}
@Test
void canWriteResource() {
assertThat(converter.canWrite(Resource.class, new MediaType("application", "octet-stream"))).isTrue();
assertThat(converter.canWrite(Resource.class, MediaType.APPLICATION_OCTET_STREAM)).isTrue();
assertThat(converter.canWrite(Resource.class, MediaType.ALL)).isTrue();
assertThat(converter.canWrite(ByteArrayResource.class, MediaType.ALL)).isTrue();
}
@Test
@@ -73,6 +77,17 @@ class ResourceHttpMessageConverterTests {
assertThat(actualResource.getFilename()).isEqualTo("yourlogo.jpg");
}
@Test // gh-36368
void shouldNotReadAsUnknownType() throws IOException {
byte[] body = FileCopyUtils.copyToByteArray(getClass().getResourceAsStream("logo.jpg"));
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body);
inputMessage.getHeaders().setContentType(MediaType.IMAGE_JPEG);
inputMessage.getHeaders().setContentDisposition(
ContentDisposition.attachment().filename("yourlogo.jpg").build());
assertThatExceptionOfType(HttpMessageNotReadableException.class).isThrownBy(() ->
converter.read(CustomResource.class, inputMessage));
}
@Test // SPR-13443
public void shouldReadInputStreamResource() throws IOException {
try (InputStream body = getClass().getResourceAsStream("logo.jpg") ) {
@@ -100,6 +115,16 @@ class ResourceHttpMessageConverterTests {
}
}
@Test // gh-36368
public void shouldNotReadStreamResourceAsUnknownType() throws IOException {
try (InputStream body = getClass().getResourceAsStream("logo.jpg") ) {
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body);
inputMessage.getHeaders().setContentType(MediaType.IMAGE_JPEG);
assertThatExceptionOfType(HttpMessageNotReadableException.class).isThrownBy(() ->
converter.read(CustomStreamResource.class, inputMessage));
}
}
@Test
void shouldWriteImageResource() throws IOException {
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
@@ -157,4 +182,19 @@ class ResourceHttpMessageConverterTests {
assertThat(outputMessage.getHeaders().getContentLength()).isEqualTo(0);
}
static class CustomStreamResource extends InputStreamResource {
public CustomStreamResource(InputStreamSource inputStreamSource) {
super(inputStreamSource);
}
}
static class CustomResource extends ByteArrayResource {
public CustomResource(byte[] byteArray) {
super(byteArray);
}
}
}