From 124582d910ac0573dfa615e02973d9f42326c4a0 Mon Sep 17 00:00:00 2001 From: whl Date: Sun, 20 Apr 2025 13:53:47 +0800 Subject: [PATCH] Fix expansion of query param with same name See gh-34783 Signed-off-by: whl --- .../web/util/HierarchicalUriComponents.java | 2 +- .../web/util/UriComponentsBuilderTests.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java index 3af171ebc9..e7d156f0ca 100644 --- a/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/HierarchicalUriComponents.java @@ -451,7 +451,7 @@ final class HierarchicalUriComponents extends UriComponents { UriTemplateVariables queryVariables = new QueryUriTemplateVariables(variables); this.queryParams.forEach((key, values) -> { String name = expandUriComponent(key, queryVariables, this.variableEncoder); - List expandedValues = new ArrayList<>(values.size()); + List expandedValues = result.getOrDefault(name, new ArrayList<>(values.size())); for (String value : values) { expandedValues.add(expandUriComponent(value, queryVariables, this.variableEncoder)); } diff --git a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java index f31c71bb1a..6376a680db 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriComponentsBuilderTests.java @@ -629,6 +629,20 @@ class UriComponentsBuilderTests { assertThat(uri.toString()).isEqualTo("ws://example.org:7777/path?q=1#foo"); } + @ParameterizedTest + @EnumSource + void parseBuildAndExpandHierarchicalWithDuplicateQueryKeys(ParserType parserType) { + UriComponents result = UriComponentsBuilder.fromUriString("/?{pk1}={pv1}&{pk2}={pv2}", parserType) + .buildAndExpand("k1", "v1", "k1", "v2"); + assertThat(result.getQuery()).isEqualTo("k1=v1&k1=v2"); + assertThat(result.getQueryParams().get("k1")).containsExactly("v1", "v2"); + + UriComponents result2 = UriComponentsBuilder.fromUriString("/?{pk1}={pv1}&{pk2}={pv2}", parserType) + .buildAndExpand(Map.of("pk1", "k1", "pv1", "v1", "pk2", "k1", "pv2", "v2")); + assertThat(result2.getQuery()).isEqualTo("k1=v1&k1=v2"); + assertThat(result.getQueryParams().get("k1")).containsExactly("v1", "v2"); + } + @ParameterizedTest @EnumSource void buildAndExpandOpaque(ParserType parserType) {