diff --git a/spring-web/src/main/java/org/springframework/http/ReadOnlyHttpHeaders.java b/spring-web/src/main/java/org/springframework/http/ReadOnlyHttpHeaders.java index a6e52face5..ff129f7a0c 100644 --- a/spring-web/src/main/java/org/springframework/http/ReadOnlyHttpHeaders.java +++ b/spring-web/src/main/java/org/springframework/http/ReadOnlyHttpHeaders.java @@ -16,9 +16,10 @@ package org.springframework.http; -import java.util.AbstractMap; +import java.util.AbstractMap.SimpleImmutableEntry; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -31,6 +32,7 @@ import org.springframework.util.MultiValueMap; * {@code HttpHeaders} object that can only be read, not written to. * * @author Brian Clozel + * @author Sam Brannen * @since 5.1.1 */ class ReadOnlyHttpHeaders extends HttpHeaders { @@ -141,9 +143,10 @@ class ReadOnlyHttpHeaders extends HttpHeaders { @Override public Set>> entrySet() { - return Collections.unmodifiableSet(this.headers.entrySet().stream() - .map(AbstractMap.SimpleImmutableEntry::new) - .collect(Collectors.toSet())); + return this.headers.entrySet().stream().map(SimpleImmutableEntry::new) + .collect(Collectors.collectingAndThen( + Collectors.toCollection(LinkedHashSet::new), // Retain original ordering of entries + Collections::unmodifiableSet)); } } diff --git a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java index 15367f54ae..a749edf9ea 100644 --- a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java +++ b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java @@ -32,6 +32,7 @@ import java.util.EnumSet; import java.util.GregorianCalendar; import java.util.List; import java.util.Locale; +import java.util.Map.Entry; import java.util.TimeZone; import org.junit.jupiter.api.Test; @@ -597,4 +598,20 @@ public class HttpHeadersTests { assertThat(headers.get(headerName).get(0)).isEqualTo(headerValue); } + @Test + public void readOnlyHttpHeadersRetainEntrySetOrder() { + headers.add("aardvark", "enigma"); + headers.add("beaver", "enigma"); + headers.add("cat", "enigma"); + headers.add("dog", "enigma"); + headers.add("elephant", "enigma"); + + String[] expectedKeys = new String[] { "aardvark", "beaver", "cat", "dog", "elephant" }; + + assertArrayEquals(expectedKeys, headers.entrySet().stream().map(Entry::getKey).toArray()); + + HttpHeaders readOnlyHttpHeaders = HttpHeaders.readOnlyHttpHeaders(headers); + assertArrayEquals(expectedKeys, readOnlyHttpHeaders.entrySet().stream().map(Entry::getKey).toArray()); + } + }