From 98030f37946353569b97e65fd50337412043b941 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 6 Jun 2020 17:44:02 +0200 Subject: [PATCH 1/5] Avoid unnecessary copy of cookies map in DefaultWebClientBuilder See gh-25034 --- .../client/DefaultWebClientBuilder.java | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java index dfd1087598b..8ed5069ad7e 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java @@ -223,8 +223,8 @@ final class DefaultWebClientBuilder implements WebClient.Builder { return this; } - @SuppressWarnings("deprecation") @Override + @Deprecated public WebClient.Builder exchangeStrategies(Consumer configurer) { if (this.strategiesConfigurers == null) { this.strategiesConfigurers = new ArrayList<>(4); @@ -260,8 +260,8 @@ final class DefaultWebClientBuilder implements WebClient.Builder { .map(filter -> filter.apply(exchange)) .orElse(exchange) : exchange); return new DefaultWebClient(filteredExchange, initUriBuilderFactory(), - this.defaultHeaders != null ? unmodifiableCopy(this.defaultHeaders) : null, - this.defaultCookies != null ? unmodifiableCopy(this.defaultCookies) : null, + this.defaultHeaders != null ? HttpHeaders.readOnlyHttpHeaders(this.defaultHeaders) : null, + this.defaultCookies != null ? CollectionUtils.unmodifiableMultiValueMap(this.defaultCookies) : null, this.defaultRequest, new DefaultWebClientBuilder(this)); } @@ -280,12 +280,10 @@ final class DefaultWebClientBuilder implements WebClient.Builder { private ExchangeStrategies initExchangeStrategies() { if (CollectionUtils.isEmpty(this.strategiesConfigurers)) { - return this.strategies != null ? this.strategies : ExchangeStrategies.withDefaults(); + return (this.strategies != null ? this.strategies : ExchangeStrategies.withDefaults()); } - ExchangeStrategies.Builder builder = - this.strategies != null ? this.strategies.mutate() : ExchangeStrategies.builder(); - + (this.strategies != null ? this.strategies.mutate() : ExchangeStrategies.builder()); this.strategiesConfigurers.forEach(configurer -> configurer.accept(builder)); return builder.build(); } @@ -294,18 +292,10 @@ final class DefaultWebClientBuilder implements WebClient.Builder { if (this.uriBuilderFactory != null) { return this.uriBuilderFactory; } - DefaultUriBuilderFactory factory = this.baseUrl != null ? - new DefaultUriBuilderFactory(this.baseUrl) : new DefaultUriBuilderFactory(); + DefaultUriBuilderFactory factory = (this.baseUrl != null ? + new DefaultUriBuilderFactory(this.baseUrl) : new DefaultUriBuilderFactory()); factory.setDefaultUriVariables(this.defaultUriVariables); return factory; } - private static HttpHeaders unmodifiableCopy(HttpHeaders headers) { - return HttpHeaders.readOnlyHttpHeaders(headers); - } - - private static MultiValueMap unmodifiableCopy(MultiValueMap map) { - return CollectionUtils.unmodifiableMultiValueMap(new LinkedMultiValueMap<>(map)); - } - } From 7244f0306422e6306c54f7fe2ee8414259a34c94 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 6 Jun 2020 17:44:30 +0200 Subject: [PATCH 2/5] Avoid unnecessary creation of not-found entity in ResponseEntity#of Closes gh-25183 --- .../springframework/http/ResponseEntity.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/ResponseEntity.java b/spring-web/src/main/java/org/springframework/http/ResponseEntity.java index 9e07f703f43..f9df9eb3a16 100644 --- a/spring-web/src/main/java/org/springframework/http/ResponseEntity.java +++ b/spring-web/src/main/java/org/springframework/http/ResponseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -217,19 +217,6 @@ public class ResponseEntity extends HttpEntity { return new DefaultBuilder(status); } - /** - * A shortcut for creating a {@code ResponseEntity} with the given body - * and the {@linkplain HttpStatus#OK OK} status, or an empty body and a - * {@linkplain HttpStatus#NOT_FOUND NOT FOUND} status in case of an - * {@linkplain Optional#empty()} parameter. - * @return the created {@code ResponseEntity} - * @since 5.1 - */ - public static ResponseEntity of(Optional body) { - Assert.notNull(body, "Body must not be null"); - return body.map(ResponseEntity::ok).orElse(notFound().build()); - } - /** * Create a builder with the status set to {@linkplain HttpStatus#OK OK}. * @return the created builder @@ -246,8 +233,20 @@ public class ResponseEntity extends HttpEntity { * @since 4.1 */ public static ResponseEntity ok(T body) { - BodyBuilder builder = ok(); - return builder.body(body); + return ok().body(body); + } + + /** + * A shortcut for creating a {@code ResponseEntity} with the given body + * and the {@linkplain HttpStatus#OK OK} status, or an empty body and a + * {@linkplain HttpStatus#NOT_FOUND NOT FOUND} status in case of an + * {@linkplain Optional#empty()} parameter. + * @return the created {@code ResponseEntity} + * @since 5.1 + */ + public static ResponseEntity of(Optional body) { + Assert.notNull(body, "Body must not be null"); + return body.map(ResponseEntity::ok).orElseGet(() -> notFound().build()); } /** @@ -258,8 +257,7 @@ public class ResponseEntity extends HttpEntity { * @since 4.1 */ public static BodyBuilder created(URI location) { - BodyBuilder builder = status(HttpStatus.CREATED); - return builder.location(location); + return status(HttpStatus.CREATED).location(location); } /** From d71957ce7c2d4c77e551177c89ace2e3b95c3b2a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 6 Jun 2020 17:45:12 +0200 Subject: [PATCH 3/5] Polishing --- .../http/server/reactive/MockServerHttpRequest.java | 12 ++++-------- .../http/server/reactive/MockServerHttpRequest.java | 12 ++++-------- .../reactive/config/WebFluxConfigurationSupport.java | 1 + 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java index 2488bdfc036..e938fc50024 100644 --- a/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/http/server/reactive/MockServerHttpRequest.java @@ -78,7 +78,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { private MockServerHttpRequest(@Nullable HttpMethod httpMethod, @Nullable String customHttpMethod, URI uri, @Nullable String contextPath, HttpHeaders headers, MultiValueMap cookies, - @Nullable InetSocketAddress remoteAddress, @Nullable InetSocketAddress localAddress, + @Nullable InetSocketAddress localAddress, @Nullable InetSocketAddress remoteAddress, @Nullable SslInfo sslInfo, Publisher body) { super(uri, contextPath, headers); @@ -86,8 +86,8 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { this.httpMethod = httpMethod; this.customHttpMethod = customHttpMethod; this.cookies = cookies; - this.remoteAddress = remoteAddress; this.localAddress = localAddress; + this.remoteAddress = remoteAddress; this.sslInfo = sslInfo; this.body = Flux.from(body); } @@ -382,9 +382,9 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { * @see BodyBuilder#body(String) */ MockServerHttpRequest build(); - } + /** * A builder that adds a body to the request. */ @@ -423,7 +423,6 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { * @return the built request entity */ MockServerHttpRequest body(String body); - } @@ -431,7 +430,6 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { private static final DataBufferFactory BUFFER_FACTORY = new DefaultDataBufferFactory(); - @Nullable private final HttpMethod method; @@ -612,7 +610,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { public MockServerHttpRequest body(Publisher body) { applyCookiesIfNecessary(); return new MockServerHttpRequest(this.method, this.customMethod, getUrlToUse(), this.contextPath, - this.headers, this.cookies, this.remoteAddress, this.localAddress, this.sslInfo, body); + this.headers, this.cookies, this.localAddress, this.remoteAddress, this.sslInfo, body); } private void applyCookiesIfNecessary() { @@ -625,11 +623,9 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { private URI getUrlToUse() { MultiValueMap params = this.queryParamsBuilder.buildAndExpand().encode().getQueryParams(); - if (!params.isEmpty()) { return UriComponentsBuilder.fromUri(this.url).queryParams(params).build(true).toUri(); } - return this.url; } } diff --git a/spring-web/src/testFixtures/java/org/springframework/web/testfixture/http/server/reactive/MockServerHttpRequest.java b/spring-web/src/testFixtures/java/org/springframework/web/testfixture/http/server/reactive/MockServerHttpRequest.java index 4f0ab79882b..70a566f199a 100644 --- a/spring-web/src/testFixtures/java/org/springframework/web/testfixture/http/server/reactive/MockServerHttpRequest.java +++ b/spring-web/src/testFixtures/java/org/springframework/web/testfixture/http/server/reactive/MockServerHttpRequest.java @@ -78,7 +78,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { private MockServerHttpRequest(@Nullable HttpMethod httpMethod, @Nullable String customHttpMethod, URI uri, @Nullable String contextPath, HttpHeaders headers, MultiValueMap cookies, - @Nullable InetSocketAddress remoteAddress, @Nullable InetSocketAddress localAddress, + @Nullable InetSocketAddress localAddress, @Nullable InetSocketAddress remoteAddress, @Nullable SslInfo sslInfo, Publisher body) { super(uri, contextPath, headers); @@ -86,8 +86,8 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { this.httpMethod = httpMethod; this.customHttpMethod = customHttpMethod; this.cookies = cookies; - this.remoteAddress = remoteAddress; this.localAddress = localAddress; + this.remoteAddress = remoteAddress; this.sslInfo = sslInfo; this.body = Flux.from(body); } @@ -382,9 +382,9 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { * @see BodyBuilder#body(String) */ MockServerHttpRequest build(); - } + /** * A builder that adds a body to the request. */ @@ -423,7 +423,6 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { * @return the built request entity */ MockServerHttpRequest body(String body); - } @@ -431,7 +430,6 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { private static final DataBufferFactory BUFFER_FACTORY = new DefaultDataBufferFactory(); - @Nullable private final HttpMethod method; @@ -612,7 +610,7 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { public MockServerHttpRequest body(Publisher body) { applyCookiesIfNecessary(); return new MockServerHttpRequest(this.method, this.customMethod, getUrlToUse(), this.contextPath, - this.headers, this.cookies, this.remoteAddress, this.localAddress, this.sslInfo, body); + this.headers, this.cookies, this.localAddress, this.remoteAddress, this.sslInfo, body); } private void applyCookiesIfNecessary() { @@ -625,11 +623,9 @@ public final class MockServerHttpRequest extends AbstractServerHttpRequest { private URI getUrlToUse() { MultiValueMap params = this.queryParamsBuilder.buildAndExpand().encode().getQueryParams(); - if (!params.isEmpty()) { return UriComponentsBuilder.fromUri(this.url).queryParams(params).build(true).toUri(); } - return this.url; } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java index 02283d1eb16..e7061ce4255 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java @@ -273,6 +273,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { ServerCodecConfigurer serverCodecConfigurer, @Qualifier("webFluxConversionService") FormattingConversionService conversionService, @Qualifier("webFluxValidator") Validator validator) { + RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); adapter.setMessageReaders(serverCodecConfigurer.getReaders()); adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator)); From 65154170d39cd4cb53c65e062b1c8e54ca0019f9 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 6 Jun 2020 18:49:32 +0200 Subject: [PATCH 4/5] Polishing --- .../main/java/org/springframework/http/RequestEntity.java | 4 +++- .../java/org/springframework/http/ResponseEntity.java | 4 ++++ .../web/reactive/function/client/DefaultWebClient.java | 5 +---- .../reactive/function/client/DefaultWebClientBuilder.java | 8 ++++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/RequestEntity.java b/spring-web/src/main/java/org/springframework/http/RequestEntity.java index 19133210db7..34255c4d5cc 100644 --- a/spring-web/src/main/java/org/springframework/http/RequestEntity.java +++ b/spring-web/src/main/java/org/springframework/http/RequestEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -70,6 +70,8 @@ import org.springframework.util.ObjectUtils; * @param the body type * @see #getMethod() * @see #getUrl() + * @see org.springframework.web.client.RestOperations#exchange(RequestEntity, Class) + * @see ResponseEntity */ public class RequestEntity extends HttpEntity { diff --git a/spring-web/src/main/java/org/springframework/http/ResponseEntity.java b/spring-web/src/main/java/org/springframework/http/ResponseEntity.java index f9df9eb3a16..591b56606f9 100644 --- a/spring-web/src/main/java/org/springframework/http/ResponseEntity.java +++ b/spring-web/src/main/java/org/springframework/http/ResponseEntity.java @@ -70,6 +70,10 @@ import org.springframework.util.ObjectUtils; * @since 3.0.2 * @param the body type * @see #getStatusCode() + * @see org.springframework.web.client.RestOperations#getForEntity(String, Class, Object...) + * @see org.springframework.web.client.RestOperations#getForEntity(String, Class, java.util.Map) + * @see org.springframework.web.client.RestOperations#getForEntity(URI, Class) + * @see RequestEntity */ public class ResponseEntity extends HttpEntity { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java index 4803d3811af..9657d5def55 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java @@ -417,26 +417,23 @@ class DefaultWebClient implements WebClient { private static class DefaultResponseSpec implements ResponseSpec { - private static final IntPredicate STATUS_CODE_ERROR = value -> value >= 400; + private static final IntPredicate STATUS_CODE_ERROR = (value -> value >= 400); private static final StatusHandler DEFAULT_STATUS_HANDLER = new StatusHandler(STATUS_CODE_ERROR, ClientResponse::createException); - private final Mono responseMono; private final Supplier requestSupplier; private final List statusHandlers = new ArrayList<>(1); - DefaultResponseSpec(Mono responseMono, Supplier requestSupplier) { this.responseMono = responseMono; this.requestSupplier = requestSupplier; this.statusHandlers.add(DEFAULT_STATUS_HANDLER); } - @Override public ResponseSpec onStatus(Predicate statusPredicate, Function> exceptionFunction) { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java index 8ed5069ad7e..3b52090258b 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClientBuilder.java @@ -101,6 +101,7 @@ final class DefaultWebClientBuilder implements WebClient.Builder { this.defaultUriVariables = (other.defaultUriVariables != null ? new LinkedHashMap<>(other.defaultUriVariables) : null); this.uriBuilderFactory = other.uriBuilderFactory; + if (other.defaultHeaders != null) { this.defaultHeaders = new HttpHeaders(); this.defaultHeaders.putAll(other.defaultHeaders); @@ -108,13 +109,16 @@ final class DefaultWebClientBuilder implements WebClient.Builder { else { this.defaultHeaders = null; } + this.defaultCookies = (other.defaultCookies != null ? new LinkedMultiValueMap<>(other.defaultCookies) : null); this.defaultRequest = other.defaultRequest; - this.filters = other.filters != null ? new ArrayList<>(other.filters) : null; + this.filters = (other.filters != null ? new ArrayList<>(other.filters) : null); + this.connector = other.connector; this.strategies = other.strategies; - this.strategiesConfigurers = other.strategiesConfigurers != null ? new ArrayList<>(other.strategiesConfigurers) : null; + this.strategiesConfigurers = (other.strategiesConfigurers != null ? + new ArrayList<>(other.strategiesConfigurers) : null); this.exchangeFunction = other.exchangeFunction; } From d01830355d106cd87108a67fefda1c621e2e6ea6 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 6 Jun 2020 18:49:47 +0200 Subject: [PATCH 5/5] Upgrade to Jetty Reactive HttpClient 1.1.3 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4bbb3433593..1d32d1af139 100644 --- a/build.gradle +++ b/build.gradle @@ -152,7 +152,7 @@ configure(allprojects) { project -> dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") { exclude group: "commons-logging", name: "commons-logging" } - dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.2" + dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.3" dependency "org.jruby:jruby:9.2.11.1" dependency "org.python:jython-standalone:2.7.1"