From 1d58fac54d6d4d67e4921596df9beb50fe94b9d1 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 11 Sep 2018 15:15:15 +0200 Subject: [PATCH] UriComponentsBuilder copies query params through MultiValueMap.addAll Issue: SPR-17256 --- .../util/LinkedMultiValueMap.java | 10 ++++++++-- .../web/util/UriComponentsBuilder.java | 2 +- .../web/util/UriComponentsBuilderTests.java | 16 ++++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/LinkedMultiValueMap.java b/spring-core/src/main/java/org/springframework/util/LinkedMultiValueMap.java index b510e64e31..f4d3a85e73 100644 --- a/spring-core/src/main/java/org/springframework/util/LinkedMultiValueMap.java +++ b/spring-core/src/main/java/org/springframework/util/LinkedMultiValueMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -117,7 +117,6 @@ public class LinkedMultiValueMap implements MultiValueMap, Serializa public Map toSingleValueMap() { LinkedHashMap singleValueMap = new LinkedHashMap<>(this.targetMap.size()); this.targetMap.forEach((key, value) -> singleValueMap.put(key, value.get(0))); - return singleValueMap; } @@ -191,7 +190,10 @@ public class LinkedMultiValueMap implements MultiValueMap, Serializa /** * Create a deep copy of this Map. * @return a copy of this Map, including a copy of each value-holding List entry + * (consistently using an independent modifiable {@link LinkedList} for each entry) + * along the lines of {@code MultiValueMap.addAll} semantics * @since 4.2 + * @see #addAll(MultiValueMap) * @see #clone() */ public LinkedMultiValueMap deepCopy() { @@ -203,7 +205,11 @@ public class LinkedMultiValueMap implements MultiValueMap, Serializa /** * Create a regular copy of this Map. * @return a shallow copy of this Map, reusing this Map's value-holding List entries + * (even if some entries are shared or unmodifiable) along the lines of standard + * {@code Map.put} semantics * @since 4.2 + * @see #put(Object, List) + * @see #putAll(Map) * @see LinkedMultiValueMap#LinkedMultiValueMap(Map) * @see #deepCopy() */ diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java index e07e6084bb..7d3fd58dcd 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponentsBuilder.java @@ -705,7 +705,7 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable { @Override public UriComponentsBuilder queryParams(@Nullable MultiValueMap params) { if (params != null) { - this.queryParams.putAll(params); + this.queryParams.addAll(params); } return this; } 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 de504641a7..4d41aefe85 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 @@ -36,13 +36,15 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; /** - * Unit tests for {@link org.springframework.web.util.UriComponentsBuilder}. + * Unit tests for {@link UriComponentsBuilder}. * * @author Arjen Poutsma + * @author Rossen Stoyanchev * @author Phillip Webb * @author Oliver Gierke - * @author David Eckel + * @author Juergen Hoeller * @author Sam Brannen + * @author David Eckel */ public class UriComponentsBuilderTests { @@ -902,9 +904,19 @@ public class UriComponentsBuilderTests { public void uriComponentsNotEqualAfterNormalization() { UriComponents uri1 = UriComponentsBuilder.fromUriString("http://test.com").build().normalize(); UriComponents uri2 = UriComponentsBuilder.fromUriString("http://test.com/").build(); + assertTrue(uri1.getPathSegments().isEmpty()); assertTrue(uri2.getPathSegments().isEmpty()); assertNotEquals(uri1, uri2); } + @Test // SPR-17256 + public void uriComponentsWithMergedQueryParams() { + String uri = UriComponentsBuilder.fromUriString("http://localhost:8081") + .uriComponents(UriComponentsBuilder.fromUriString("/{path}?sort={sort}").build()) + .queryParam("sort", "another_value").build().toString(); + + assertEquals("http://localhost:8081/{path}?sort={sort}&sort=another_value", uri); + } + }