diff --git a/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java index 814be21ba14a..b1c5bf1136f4 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/ResourceRegionHttpMessageConverter.java @@ -140,19 +140,15 @@ protected MediaType getDefaultContentType(Object object) { @Override protected boolean supportsRepeatableWrites(Object object) { - if (object instanceof ResourceRegion resourceRegion) { - return supportsRepeatableWrites(resourceRegion); - } - else { - @SuppressWarnings("unchecked") - Collection regions = (Collection) object; - for (ResourceRegion region : regions) { - if (!supportsRepeatableWrites(region)) { - return false; - } - } - return true; - } + return (object instanceof ResourceRegion resourceRegion) ? + supportsRepeatableWrites(resourceRegion) : + supportsRepeatableWritesInRegionCollection(object); + } + + private boolean supportsRepeatableWritesInRegionCollection(Object object) { + @SuppressWarnings("unchecked") + Collection resourceRegions = (Collection) object; + return resourceRegions.stream().allMatch(this::supportsRepeatableWrites); } private boolean supportsRepeatableWrites(ResourceRegion region) { diff --git a/spring-web/src/test/java/org/springframework/http/converter/ResourceRegionHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/ResourceRegionHttpMessageConverterTests.java index e538f9013cf0..75ba0b1f6b5b 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/ResourceRegionHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/ResourceRegionHttpMessageConverterTests.java @@ -22,8 +22,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.io.ClassPathResource; @@ -181,6 +185,26 @@ void partialContentMultipleByteRangesInRandomOrderAndOverlapping() throws Except assertThat(ranges[15]).isEqualTo("t resource"); } + @Test + void testSingleResourceRegionSupportsRepeatableWrites() { + ResourceRegion region = mock(ResourceRegion.class); + assertThat(converter.supportsRepeatableWrites(region)).isTrue(); + } + + @ParameterizedTest + @MethodSource("regionCollections") + void testCollectionOfResourceRegionSupportsRepeatableWrites(Object regionCollection, boolean expected) { + assertThat(converter.supportsRepeatableWrites(regionCollection)).isEqualTo(expected); + } + + static Stream regionCollections() { + return Stream.of( + Arguments.of(Collections.emptyList(), true), + Arguments.of(Collections.singletonList(mock(ResourceRegion.class)), true), + Arguments.of(List.of(mock(ResourceRegion.class), mock(ResourceRegion.class)), true) + ); + } + @Test // SPR-15041 public void applicationOctetStreamDefaultContentType() throws Exception { MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();