From beb415dfa370baae5098b65fa56a76c9936d5ac9 Mon Sep 17 00:00:00 2001 From: Patrick Strawderman Date: Tue, 20 Feb 2024 17:16:56 -0800 Subject: [PATCH 1/2] Optimize HttpHeaders.getAcceptLanguageAsLocales The HttpHeaders.getAcceptLanguageAsLocales was incurring overhead from using a Stream, as well as calling the fairly expensive Locale.getDisplayName method. Switch to using an ArrayList, and skipping over wildcard ranges to avoid needing to check the display name. Closes gh-32318 --- .../java/org/springframework/http/HttpHeaders.java | 12 ++++++++---- .../org/springframework/http/HttpHeadersTests.java | 13 +++++++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java index d1656fbf843..601cd1b3a61 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java +++ b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java @@ -527,10 +527,14 @@ public class HttpHeaders implements MultiValueMap, Serializable if (ranges.isEmpty()) { return Collections.emptyList(); } - return ranges.stream() - .map(range -> Locale.forLanguageTag(range.getRange())) - .filter(locale -> StringUtils.hasText(locale.getDisplayName())) - .toList(); + + List locales = new ArrayList<>(ranges.size()); + for (Locale.LanguageRange range : ranges) { + if (!range.getRange().startsWith("*")) { + locales.add(Locale.forLanguageTag(range.getRange())); + } + } + return locales; } /** 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 18696a7a160..6b4d27f034d 100644 --- a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java +++ b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java @@ -471,22 +471,27 @@ class HttpHeadersTests { @Test void acceptLanguage() { - String headerValue = "fr-ch, fr;q=0.9, en-*;q=0.8, de;q=0.7, *;q=0.5"; + String headerValue = "fr-ch, fr;q=0.9, en-*;q=0.8, de;q=0.7, *-us;q=0.6, *;q=0.5"; headers.setAcceptLanguage(Locale.LanguageRange.parse(headerValue)); assertThat(headers.getFirst(HttpHeaders.ACCEPT_LANGUAGE)).isEqualTo(headerValue); - List expectedRanges = Arrays.asList( + List expectedRanges = List.of( new Locale.LanguageRange("fr-ch"), new Locale.LanguageRange("fr", 0.9), new Locale.LanguageRange("en-*", 0.8), new Locale.LanguageRange("de", 0.7), + new Locale.LanguageRange("*-us", 0.6), new Locale.LanguageRange("*", 0.5) ); assertThat(headers.getAcceptLanguage()).isEqualTo(expectedRanges); - assertThat(headers.getAcceptLanguageAsLocales()).element(0).isEqualTo(Locale.forLanguageTag("fr-ch")); + assertThat(headers.getAcceptLanguageAsLocales()).isEqualTo(List.of( + Locale.forLanguageTag("fr-ch"), + Locale.forLanguageTag("fr"), + Locale.forLanguageTag("en"), + Locale.forLanguageTag("de"))); headers.setAcceptLanguageAsLocales(Collections.singletonList(Locale.FRANCE)); - assertThat(headers.getAcceptLanguageAsLocales()).element(0).isEqualTo(Locale.FRANCE); + assertThat(headers.getAcceptLanguageAsLocales()).first().isEqualTo(Locale.FRANCE); } @Test // SPR-15603 From 33705516ffc546c367eba7d7c24a9bbf97f85181 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Thu, 29 Feb 2024 15:51:29 +0100 Subject: [PATCH 2/2] Polishing external contribution See gh-32318 --- .../test/java/org/springframework/http/HttpHeadersTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 6b4d27f034d..059e3a98162 100644 --- a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java +++ b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java @@ -484,11 +484,11 @@ class HttpHeadersTests { new Locale.LanguageRange("*", 0.5) ); assertThat(headers.getAcceptLanguage()).isEqualTo(expectedRanges); - assertThat(headers.getAcceptLanguageAsLocales()).isEqualTo(List.of( + assertThat(headers.getAcceptLanguageAsLocales()).containsExactly( Locale.forLanguageTag("fr-ch"), Locale.forLanguageTag("fr"), Locale.forLanguageTag("en"), - Locale.forLanguageTag("de"))); + Locale.forLanguageTag("de")); headers.setAcceptLanguageAsLocales(Collections.singletonList(Locale.FRANCE)); assertThat(headers.getAcceptLanguageAsLocales()).first().isEqualTo(Locale.FRANCE);