From db53b618c12da87b1bd7bea85f11a2f94015a0b2 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 5 Dec 2022 11:15:51 +0000 Subject: [PATCH] Simplify form data handling in HttpRequestValues Closes gh-29615 --- .../service/invoker/HttpRequestValues.java | 20 +------------- .../invoker/HttpRequestValuesTests.java | 7 ++--- .../RequestParamArgumentResolverTests.java | 10 ++++--- .../WebClientHttpServiceProxyTests.java | 27 ++++++++++++++++--- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpRequestValues.java b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpRequestValues.java index e108f8418da2..090ec54859fb 100644 --- a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpRequestValues.java +++ b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpRequestValues.java @@ -17,14 +17,11 @@ package org.springframework.web.service.invoker; import java.net.URI; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; import org.reactivestreams.Publisher; @@ -34,7 +31,6 @@ import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.client.MultipartBodyBuilder; -import org.springframework.http.codec.FormHttpMessageWriter; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -202,8 +198,6 @@ public static Builder builder() { */ public final static class Builder { - private static final Function, byte[]> FORM_DATA_SERIALIZER = new FormDataSerializer(); - @Nullable private HttpMethod httpMethod; @@ -403,7 +397,7 @@ public HttpRequestValues build() { if (isFormData) { Assert.isTrue(bodyValue == null && this.body == null, "Expected body or request params, not both"); - bodyValue = FORM_DATA_SERIALIZER.apply(this.requestParams); + bodyValue = new LinkedMultiValueMap<>(this.requestParams); } else if (uri != null) { uri = UriComponentsBuilder.fromUri(uri) @@ -458,16 +452,4 @@ private String appendQueryParams( } - - private static class FormDataSerializer - extends FormHttpMessageWriter implements Function, byte[]> { - - @Override - public byte[] apply(MultiValueMap requestParams) { - Charset charset = StandardCharsets.UTF_8; - return serializeForm(requestParams, charset).getBytes(charset); - } - - } - } diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpRequestValuesTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpRequestValuesTests.java index 850eb3ea9742..7d2428975db7 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpRequestValuesTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpRequestValuesTests.java @@ -17,6 +17,7 @@ package org.springframework.web.service.invoker; import java.net.URI; +import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -29,7 +30,6 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.util.UriComponentsBuilder; -import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; /** @@ -58,8 +58,9 @@ void requestParamAsFormData(String httpMethod) { .build(); Object body = requestValues.getBodyValue(); - assertThat(body).isNotNull().isInstanceOf(byte[].class); - assertThat(new String((byte[]) body, UTF_8)).isEqualTo("param1=1st+value¶m2=2nd+value+A¶m2=2nd+value+B"); + assertThat((MultiValueMap) body).hasSize(2) + .containsEntry("param1", List.of("1st value")) + .containsEntry("param2", List.of("2nd value A", "2nd value B")); } @Test diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/RequestParamArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/RequestParamArgumentResolverTests.java index e663a4cfbfc7..07da632ae8bb 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/RequestParamArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/RequestParamArgumentResolverTests.java @@ -16,13 +16,15 @@ package org.springframework.web.service.invoker; +import java.util.List; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.service.annotation.PostExchange; -import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; /** @@ -58,8 +60,10 @@ void requestParam() { this.service.postForm("value 1", "value 2"); Object body = this.client.getRequestValues().getBodyValue(); - assertThat(body).isNotNull().isInstanceOf(byte[].class); - assertThat(new String((byte[]) body, UTF_8)).isEqualTo("param1=value+1¶m2=value+2"); + assertThat(body).isNotNull().isInstanceOf(MultiValueMap.class); + assertThat((MultiValueMap) body).hasSize(2) + .containsEntry("param1", List.of("value 1")) + .containsEntry("param2", List.of("value 2")); } diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/support/WebClientHttpServiceProxyTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/support/WebClientHttpServiceProxyTests.java index 3b1e90747b4d..80d490f17e98 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/support/WebClientHttpServiceProxyTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/support/WebClientHttpServiceProxyTests.java @@ -26,6 +26,7 @@ import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -33,10 +34,14 @@ import reactor.test.StepVerifier; import org.springframework.lang.Nullable; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.service.annotation.GetExchange; +import org.springframework.web.service.annotation.PostExchange; import org.springframework.web.service.invoker.HttpServiceProxyFactory; import static org.assertj.core.api.Assertions.assertThat; @@ -68,8 +73,7 @@ void shutdown() throws IOException { @Test - void greeting() throws Exception { - + void greeting() { prepareResponse(response -> response.setHeader("Content-Type", "text/plain").setBody("Hello Spring!")); @@ -81,7 +85,6 @@ void greeting() throws Exception { @Test void greetingWithRequestAttribute() { - Map attributes = new HashMap<>(); WebClient webClient = WebClient.builder() @@ -115,6 +118,21 @@ void uri() throws Exception { assertThat(this.server.takeRequest().getRequestUrl().uri()).isEqualTo(dynamicUri); } + @Test + void formData() throws Exception { + prepareResponse(response -> response.setResponseCode(201)); + + MultiValueMap map = new LinkedMultiValueMap<>(); + map.add("param1", "value 1"); + map.add("param2", "value 2"); + + initHttpService().postForm(map); + + RecordedRequest request = this.server.takeRequest(); + assertThat(request.getHeaders().get("Content-Type")).isEqualTo("application/x-www-form-urlencoded;charset=UTF-8"); + assertThat(request.getBody().readUtf8()).isEqualTo("param1=value+1¶m2=value+2"); + } + private TestHttpService initHttpService() { WebClient webClient = WebClient.builder().baseUrl(this.server.url("/").toString()).build(); return initHttpService(webClient); @@ -145,6 +163,9 @@ private interface TestHttpService { @GetExchange("/greetings/{id}") String getGreetingById(@Nullable URI uri, @PathVariable String id); + @PostExchange(contentType = "application/x-www-form-urlencoded") + void postForm(@RequestParam MultiValueMap params); + } }