From 5cb3af708c91a677d86f12ce780642415cd51e48 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 17 Oct 2022 12:23:42 +0100 Subject: [PATCH] Add Builder to HttpServiceProxyFactory HttpServiceProxyFactory now support programmatic initialization through a builder, while bean-style initialization is deprecated. See gh-29296 --- .../invoker/HttpServiceProxyFactory.java | 446 +++++++++++++++--- .../CookieValueArgumentResolverTests.java | 3 +- .../HttpMethodArgumentResolverTests.java | 2 +- .../invoker/HttpServiceMethodTests.java | 10 +- .../NamedValueArgumentResolverTests.java | 5 +- .../PathVariableArgumentResolverTests.java | 2 +- ...RequestAttributeArgumentResolverTests.java | 3 +- .../RequestBodyArgumentResolverTests.java | 3 +- .../RequestHeaderArgumentResolverTests.java | 3 +- .../RequestParamArgumentResolverTests.java | 3 +- .../invoker/UrlArgumentResolverTests.java | 3 +- .../client/support/WebClientAdapter.java | 25 +- .../WebClientHttpServiceProxyTests.java | 9 +- src/docs/asciidoc/integration.adoc | 3 +- 14 files changed, 413 insertions(+), 107 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java index 42a9479182d..a3b0c49c2d1 100644 --- a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java +++ b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java @@ -43,10 +43,10 @@ import org.springframework.util.StringValueResolver; import org.springframework.web.service.annotation.HttpExchange; /** - * Factory for creating a client proxy given an HTTP service interface with + * Factory to create a client proxy from an HTTP service interface with * {@link HttpExchange @HttpExchange} methods. * - *

This class is intended to be declared as a bean in a Spring configuration. + *

To create an instance, use static methods to obtain a {@link Builder Builder}. * * @author Rossen Stoyanchev * @since 6.0 @@ -54,81 +54,98 @@ import org.springframework.web.service.annotation.HttpExchange; */ public final class HttpServiceProxyFactory implements InitializingBean, EmbeddedValueResolverAware { - private final HttpClientAdapter clientAdapter; + @Nullable + private final BuilderInitializedFactory builderInitializedFactory; @Nullable - private List customArgumentResolvers; - - @Nullable - private List argumentResolvers; - - @Nullable - private ConversionService conversionService; - - @Nullable - private StringValueResolver embeddedValueResolver; - - private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); - - private Duration blockTimeout = Duration.ofSeconds(5); + private final BeanStyleFactory beanStyleFactory; /** * Create an instance with the underlying HTTP client to use. * @param clientAdapter an adapter for the client - * @see org.springframework.web.reactive.function.client.support.WebClientAdapter#createHttpServiceProxyFactory(org.springframework.web.reactive.function.client.WebClient) + * @deprecated as of 6.0 RC1 in favor of using the Builder to initialize + * the HttpServiceProxyFactory instance. */ + @Deprecated(since = "6.0.0-RC1", forRemoval = true) public HttpServiceProxyFactory(HttpClientAdapter clientAdapter) { - Assert.notNull(clientAdapter, "HttpClientAdapter is required"); - this.clientAdapter = clientAdapter; + this.beanStyleFactory = new BeanStyleFactory(clientAdapter); + this.builderInitializedFactory = null; + } + + private HttpServiceProxyFactory( + HttpClientAdapter clientAdapter, List argumentResolvers, + @Nullable StringValueResolver embeddedValueResolver, + ReactiveAdapterRegistry reactiveAdapterRegistry, Duration blockTimeout) { + + this.beanStyleFactory = null; + this.builderInitializedFactory = new BuilderInitializedFactory( + clientAdapter, argumentResolvers, embeddedValueResolver, reactiveAdapterRegistry, blockTimeout); } /** * Register a custom argument resolver, invoked ahead of default resolvers. * @param resolver the resolver to add + * @deprecated as of 6.0 RC1 in favor of using the Builder to initialize + * the HttpServiceProxyFactory instance. */ + @Deprecated(since = "6.0.0-RC1", forRemoval = true) public void addCustomArgumentResolver(HttpServiceArgumentResolver resolver) { - if (this.customArgumentResolvers == null) { - this.customArgumentResolvers = new ArrayList<>(); - } - this.customArgumentResolvers.add(resolver); + Assert.state(this.beanStyleFactory != null, "HttpServiceProxyFactory was created through the builder"); + this.beanStyleFactory.addCustomArgumentResolver(resolver); } /** * Set the custom argument resolvers to use, ahead of default resolvers. * @param resolvers the resolvers to use + * @deprecated as of 6.0 RC1 in favor of using the Builder to initialize + * the HttpServiceProxyFactory instance. */ + @Deprecated(since = "6.0.0-RC1", forRemoval = true) public void setCustomArgumentResolvers(List resolvers) { - this.customArgumentResolvers = new ArrayList<>(resolvers); + Assert.state(this.beanStyleFactory != null, "HttpServiceProxyFactory was created through the builder"); + this.beanStyleFactory.setCustomArgumentResolvers(resolvers); } /** * Set the {@link ConversionService} to use where input values need to * be formatted as Strings. *

By default this is {@link DefaultFormattingConversionService}. + * @deprecated as of 6.0 RC1 in favor of using the Builder to initialize + * the HttpServiceProxyFactory instance. */ + @Deprecated(since = "6.0.0-RC1", forRemoval = true) public void setConversionService(ConversionService conversionService) { - this.conversionService = conversionService; + Assert.state(this.beanStyleFactory != null, "HttpServiceProxyFactory was created through the builder"); + this.beanStyleFactory.setConversionService(conversionService); } /** * Set the StringValueResolver to use for resolving placeholders and * expressions in {@link HttpExchange#url()}. * @param resolver the resolver to use + * @deprecated as of 6.0 RC1 in favor of using the Builder to initialize + * an HttpServiceProxyFactory instance. */ + @Deprecated(since = "6.0.0-RC1", forRemoval = true) @Override public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.embeddedValueResolver = resolver; + Assert.state(this.beanStyleFactory != null, "HttpServiceProxyFactory was created through the builder"); + this.beanStyleFactory.setEmbeddedValueResolver(resolver); } /** * Set the {@link ReactiveAdapterRegistry} to use to support different * asynchronous types for HTTP service method return values. *

By default this is {@link ReactiveAdapterRegistry#getSharedInstance()}. + * @deprecated as of 6.0 RC1 in favor of using the Builder to initialize + * an HttpServiceProxyFactory instance. */ + @Deprecated(since = "6.0.0-RC1", forRemoval = true) public void setReactiveAdapterRegistry(ReactiveAdapterRegistry registry) { - this.reactiveAdapterRegistry = registry; + Assert.state(this.beanStyleFactory != null, "HttpServiceProxyFactory was created through the builder"); + this.beanStyleFactory.setReactiveAdapterRegistry(registry); } /** @@ -136,42 +153,22 @@ public final class HttpServiceProxyFactory implements InitializingBean, Embedded * with a synchronous (blocking) method signature. *

By default this is 5 seconds. * @param blockTimeout the timeout value + * @deprecated as of 6.0 RC1 in favor of using the Builder to initialize + * an HttpServiceProxyFactory instance. */ + @Deprecated(since = "6.0.0-RC1", forRemoval = true) public void setBlockTimeout(Duration blockTimeout) { - this.blockTimeout = blockTimeout; + Assert.state(this.beanStyleFactory != null, "HttpServiceProxyFactory was created through the builder"); + this.beanStyleFactory.setBlockTimeout(blockTimeout); } @Override + @Deprecated public void afterPropertiesSet() throws Exception { - - this.conversionService = (this.conversionService != null ? - this.conversionService : new DefaultFormattingConversionService()); - - this.argumentResolvers = initArgumentResolvers(this.conversionService); - } - - private List initArgumentResolvers(ConversionService conversionService) { - List resolvers = new ArrayList<>(); - - // Custom - if (this.customArgumentResolvers != null) { - resolvers.addAll(this.customArgumentResolvers); + if (this.beanStyleFactory != null) { + this.beanStyleFactory.afterPropertiesSet(); } - - // Annotation-based - resolvers.add(new RequestHeaderArgumentResolver(conversionService)); - resolvers.add(new RequestBodyArgumentResolver(this.reactiveAdapterRegistry)); - resolvers.add(new PathVariableArgumentResolver(conversionService)); - resolvers.add(new RequestParamArgumentResolver(conversionService)); - resolvers.add(new CookieValueArgumentResolver(conversionService)); - resolvers.add(new RequestAttributeArgumentResolver()); - - // Specific type - resolvers.add(new UrlArgumentResolver()); - resolvers.add(new HttpMethodArgumentResolver()); - - return resolvers; } @@ -183,26 +180,163 @@ public final class HttpServiceProxyFactory implements InitializingBean, Embedded * @return the created proxy */ public S createClient(Class serviceType) { - - List httpServiceMethods = - MethodIntrospector.selectMethods(serviceType, this::isExchangeMethod).stream() - .map(method -> createHttpServiceMethod(serviceType, method)) - .toList(); - - return ProxyFactory.getProxy(serviceType, new HttpServiceMethodInterceptor(httpServiceMethods)); + if (this.builderInitializedFactory != null) { + return this.builderInitializedFactory.createClient(serviceType); + } + else if (this.beanStyleFactory != null) { + return this.beanStyleFactory.createClient(serviceType); + } + else { + throw new IllegalStateException("Expected Builder initialized or Bean-style delegate"); + } } - private boolean isExchangeMethod(Method method) { - return AnnotatedElementUtils.hasAnnotation(method, HttpExchange.class); + + /** + * Return an {@link HttpServiceProxyFactory} builder, initialized with the + * given client. + */ + public static Builder builder(HttpClientAdapter clientAdapter) { + return new Builder().clientAdapter(clientAdapter); } - private HttpServiceMethod createHttpServiceMethod(Class serviceType, Method method) { - Assert.notNull(this.argumentResolvers, - "No argument resolvers: afterPropertiesSet was not called"); + /** + * Return an {@link HttpServiceProxyFactory} builder. + */ + public static Builder builder() { + return new Builder(); + } + + + /** + * Builder to create an {@link HttpServiceProxyFactory}. + */ + public static final class Builder { + + @Nullable + private HttpClientAdapter clientAdapter; + + @Nullable + private List argumentResolvers; + + @Nullable + private ConversionService conversionService; + + @Nullable + private StringValueResolver embeddedValueResolver; + + private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); + + @Nullable + private Duration blockTimeout; + + private Builder() { + } + + /** + * Provide the HTTP client to perform requests through. + * @param clientAdapter a client adapted to {@link HttpClientAdapter} + * @return this same builder instance + */ + public Builder clientAdapter(HttpClientAdapter clientAdapter) { + this.clientAdapter = clientAdapter; + return this; + } + + /** + * Register a custom argument resolver, invoked ahead of default resolvers. + * @param resolver the resolver to add + * @return this same builder instance + */ + public Builder customArgumentResolver(HttpServiceArgumentResolver resolver) { + this.argumentResolvers = (this.argumentResolvers != null ? this.argumentResolvers : new ArrayList<>()); + this.argumentResolvers.add(resolver); + return this; + } + + /** + * Set the {@link ConversionService} to use where input values need to + * be formatted as Strings. + *

By default this is {@link DefaultFormattingConversionService}. + * @return this same builder instance + */ + public Builder conversionService(ConversionService conversionService) { + this.conversionService = conversionService; + return this; + } + + /** + * Set the {@link StringValueResolver} to use for resolving placeholders + * and expressions embedded in {@link HttpExchange#url()}. + * @param embeddedValueResolver the resolver to use + * @return this same builder instance + */ + public Builder embeddedValueResolver(StringValueResolver embeddedValueResolver) { + this.embeddedValueResolver = embeddedValueResolver; + return this; + } + + /** + * Set the {@link ReactiveAdapterRegistry} to use to support different + * asynchronous types for HTTP service method return values. + *

By default this is {@link ReactiveAdapterRegistry#getSharedInstance()}. + * @return this same builder instance + */ + public Builder reactiveAdapterRegistry(ReactiveAdapterRegistry registry) { + this.reactiveAdapterRegistry = registry; + return this; + } + + /** + * Configure how long to wait for a response for an HTTP service method + * with a synchronous (blocking) method signature. + *

By default this is 5 seconds. + * @param blockTimeout the timeout value + * @return this same builder instance + */ + public Builder blockTimeout(Duration blockTimeout) { + this.blockTimeout = blockTimeout; + return this; + } + + /** + * Build the {@link HttpServiceProxyFactory} instance. + */ + public HttpServiceProxyFactory build() { + Assert.notNull(this.clientAdapter, "HttpClientAdapter is required"); + + return new HttpServiceProxyFactory( + this.clientAdapter, initArgumentResolvers(), + this.embeddedValueResolver, this.reactiveAdapterRegistry, + (this.blockTimeout != null ? this.blockTimeout : Duration.ofSeconds(5))); + } + + private List initArgumentResolvers() { + List resolvers = new ArrayList<>(); + + // Custom + if (this.argumentResolvers != null) { + resolvers.addAll(this.argumentResolvers); + } + + ConversionService service = (this.conversionService != null ? + this.conversionService : new DefaultFormattingConversionService()); + + // Annotation-based + resolvers.add(new RequestHeaderArgumentResolver(service)); + resolvers.add(new RequestBodyArgumentResolver(this.reactiveAdapterRegistry)); + resolvers.add(new PathVariableArgumentResolver(service)); + resolvers.add(new RequestParamArgumentResolver(service)); + resolvers.add(new CookieValueArgumentResolver(service)); + resolvers.add(new RequestAttributeArgumentResolver()); + + // Specific type + resolvers.add(new UrlArgumentResolver()); + resolvers.add(new HttpMethodArgumentResolver()); + + return resolvers; + } - return new HttpServiceMethod( - method, serviceType, this.argumentResolvers, this.clientAdapter, - this.embeddedValueResolver, this.reactiveAdapterRegistry, this.blockTimeout); } @@ -235,4 +369,174 @@ public final class HttpServiceProxyFactory implements InitializingBean, Embedded } } + + /** + * Temporary class until bean-style initialization is removed. + */ + private static final class BuilderInitializedFactory { + + private final HttpClientAdapter clientAdapter; + + private final List argumentResolvers; + + @Nullable + private final StringValueResolver embeddedValueResolver; + + private final ReactiveAdapterRegistry reactiveAdapterRegistry; + + private final Duration blockTimeout; + + private BuilderInitializedFactory( + HttpClientAdapter clientAdapter, List argumentResolvers, + @Nullable StringValueResolver embeddedValueResolver, + ReactiveAdapterRegistry reactiveAdapterRegistry, Duration blockTimeout) { + + this.clientAdapter = clientAdapter; + this.argumentResolvers = argumentResolvers; + this.embeddedValueResolver = embeddedValueResolver; + this.reactiveAdapterRegistry = reactiveAdapterRegistry; + this.blockTimeout = blockTimeout; + } + + public S createClient(Class serviceType) { + + List httpServiceMethods = + MethodIntrospector.selectMethods(serviceType, this::isExchangeMethod).stream() + .map(method -> createHttpServiceMethod(serviceType, method)) + .toList(); + + return ProxyFactory.getProxy(serviceType, new HttpServiceMethodInterceptor(httpServiceMethods)); + } + + private boolean isExchangeMethod(Method method) { + return AnnotatedElementUtils.hasAnnotation(method, HttpExchange.class); + } + + private HttpServiceMethod createHttpServiceMethod(Class serviceType, Method method) { + Assert.notNull(this.argumentResolvers, + "No argument resolvers: afterPropertiesSet was not called"); + + return new HttpServiceMethod( + method, serviceType, this.argumentResolvers, this.clientAdapter, + this.embeddedValueResolver, this.reactiveAdapterRegistry, this.blockTimeout); + } + + } + + + /** + * Temporary class to support bean-style initialization during deprecation period. + */ + private static final class BeanStyleFactory implements InitializingBean, EmbeddedValueResolverAware { + + private final HttpClientAdapter clientAdapter; + + @Nullable + private List customArgumentResolvers; + + @Nullable + private List argumentResolvers; + + @Nullable + private ConversionService conversionService; + + @Nullable + private StringValueResolver embeddedValueResolver; + + private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance(); + + private Duration blockTimeout = Duration.ofSeconds(5); + + BeanStyleFactory(HttpClientAdapter clientAdapter) { + Assert.notNull(clientAdapter, "HttpClientAdapter is required"); + this.clientAdapter = clientAdapter; + } + + public void addCustomArgumentResolver(HttpServiceArgumentResolver resolver) { + if (this.customArgumentResolvers == null) { + this.customArgumentResolvers = new ArrayList<>(); + } + this.customArgumentResolvers.add(resolver); + } + + public void setCustomArgumentResolvers(List resolvers) { + this.customArgumentResolvers = new ArrayList<>(resolvers); + } + + public void setConversionService(ConversionService conversionService) { + this.conversionService = conversionService; + } + + @Override + public void setEmbeddedValueResolver(StringValueResolver resolver) { + this.embeddedValueResolver = resolver; + } + + public void setReactiveAdapterRegistry(ReactiveAdapterRegistry registry) { + this.reactiveAdapterRegistry = registry; + } + + public void setBlockTimeout(Duration blockTimeout) { + this.blockTimeout = blockTimeout; + } + + + @Override + public void afterPropertiesSet() throws Exception { + + this.conversionService = (this.conversionService != null ? + this.conversionService : new DefaultFormattingConversionService()); + + this.argumentResolvers = initArgumentResolvers(this.conversionService); + } + + private List initArgumentResolvers(ConversionService conversionService) { + List resolvers = new ArrayList<>(); + + // Custom + if (this.customArgumentResolvers != null) { + resolvers.addAll(this.customArgumentResolvers); + } + + // Annotation-based + resolvers.add(new RequestHeaderArgumentResolver(conversionService)); + resolvers.add(new RequestBodyArgumentResolver(this.reactiveAdapterRegistry)); + resolvers.add(new PathVariableArgumentResolver(conversionService)); + resolvers.add(new RequestParamArgumentResolver(conversionService)); + resolvers.add(new CookieValueArgumentResolver(conversionService)); + resolvers.add(new RequestAttributeArgumentResolver()); + + // Specific type + resolvers.add(new UrlArgumentResolver()); + resolvers.add(new HttpMethodArgumentResolver()); + + return resolvers; + } + + + public S createClient(Class serviceType) { + + List httpServiceMethods = + MethodIntrospector.selectMethods(serviceType, this::isExchangeMethod).stream() + .map(method -> createHttpServiceMethod(serviceType, method)) + .toList(); + + return ProxyFactory.getProxy(serviceType, new HttpServiceMethodInterceptor(httpServiceMethods)); + } + + private boolean isExchangeMethod(Method method) { + return AnnotatedElementUtils.hasAnnotation(method, HttpExchange.class); + } + + private HttpServiceMethod createHttpServiceMethod(Class serviceType, Method method) { + Assert.notNull(this.argumentResolvers, + "No argument resolvers: afterPropertiesSet was not called"); + + return new HttpServiceMethod( + method, serviceType, this.argumentResolvers, this.clientAdapter, + this.embeddedValueResolver, this.reactiveAdapterRegistry, this.blockTimeout); + } + + } + } diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/CookieValueArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/CookieValueArgumentResolverTests.java index e33220fe1d1..2227002bb51 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/CookieValueArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/CookieValueArgumentResolverTests.java @@ -42,8 +42,7 @@ class CookieValueArgumentResolverTests { @BeforeEach void setUp() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); - proxyFactory.afterPropertiesSet(); + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client).build(); this.service = proxyFactory.createClient(Service.class); } diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpMethodArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpMethodArgumentResolverTests.java index 23988e3641b..b74c233f4f7 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpMethodArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpMethodArgumentResolverTests.java @@ -43,7 +43,7 @@ public class HttpMethodArgumentResolverTests { @BeforeEach void setUp() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client).build(); proxyFactory.afterPropertiesSet(); this.service = proxyFactory.createClient(Service.class); } diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java index f926f52338a..baac0af3b90 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/HttpServiceMethodTests.java @@ -64,7 +64,7 @@ public class HttpServiceMethodTests { @BeforeEach void setUp() throws Exception { - this.proxyFactory = new HttpServiceProxyFactory(this.client); + this.proxyFactory = HttpServiceProxyFactory.builder(this.client).build(); this.proxyFactory.afterPropertiesSet(); } @@ -174,10 +174,10 @@ public class HttpServiceMethodTests { } @Test - void typeAndMethodAnnotatedService() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); - proxyFactory.setEmbeddedValueResolver(value -> (value.equals("${baseUrl}") ? "/base" : value)); - proxyFactory.afterPropertiesSet(); + void typeAndMethodAnnotatedService() { + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client) + .embeddedValueResolver(value -> (value.equals("${baseUrl}") ? "/base" : value)) + .build(); MethodLevelAnnotatedService service = proxyFactory.createClient(TypeAndMethodLevelAnnotatedService.class); diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/NamedValueArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/NamedValueArgumentResolverTests.java index f2029c47c84..1e710bc1070 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/NamedValueArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/NamedValueArgumentResolverTests.java @@ -61,8 +61,9 @@ class NamedValueArgumentResolverTests { @BeforeEach void setUp() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); - proxyFactory.addCustomArgumentResolver(this.argumentResolver); + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client) + .customArgumentResolver(this.argumentResolver) + .build(); proxyFactory.afterPropertiesSet(); this.service = proxyFactory.createClient(Service.class); diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/PathVariableArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/PathVariableArgumentResolverTests.java index 15d7e73ae87..2cd6283329e 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/PathVariableArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/PathVariableArgumentResolverTests.java @@ -41,7 +41,7 @@ class PathVariableArgumentResolverTests { @BeforeEach void setUp() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client).build(); proxyFactory.afterPropertiesSet(); this.service = proxyFactory.createClient(Service.class); } diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/RequestAttributeArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/RequestAttributeArgumentResolverTests.java index 8c436767623..61ec118c22c 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/RequestAttributeArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/RequestAttributeArgumentResolverTests.java @@ -40,8 +40,7 @@ class RequestAttributeArgumentResolverTests { @BeforeEach void setUp() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); - proxyFactory.afterPropertiesSet(); + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client).build(); this.service = proxyFactory.createClient(Service.class); } diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/RequestBodyArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/RequestBodyArgumentResolverTests.java index a0bd8b51f0c..1fe0d7b657e 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/RequestBodyArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/RequestBodyArgumentResolverTests.java @@ -45,8 +45,7 @@ public class RequestBodyArgumentResolverTests { @BeforeEach void setUp() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); - proxyFactory.afterPropertiesSet(); + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client).build(); this.service = proxyFactory.createClient(Service.class); } diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/RequestHeaderArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/RequestHeaderArgumentResolverTests.java index 99de8173c36..9dced7b6b5d 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/RequestHeaderArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/RequestHeaderArgumentResolverTests.java @@ -43,8 +43,7 @@ class RequestHeaderArgumentResolverTests { @BeforeEach void setUp() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); - proxyFactory.afterPropertiesSet(); + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client).build(); this.service = proxyFactory.createClient(Service.class); } 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 458c1f0f4ac..e663a4cfbfc 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 @@ -45,8 +45,7 @@ public class RequestParamArgumentResolverTests { @BeforeEach void setUp() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); - proxyFactory.afterPropertiesSet(); + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client).build(); this.service = proxyFactory.createClient(Service.class); } diff --git a/spring-web/src/test/java/org/springframework/web/service/invoker/UrlArgumentResolverTests.java b/spring-web/src/test/java/org/springframework/web/service/invoker/UrlArgumentResolverTests.java index 5089db61793..dc1a55f7e2d 100644 --- a/spring-web/src/test/java/org/springframework/web/service/invoker/UrlArgumentResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/service/invoker/UrlArgumentResolverTests.java @@ -40,8 +40,7 @@ public class UrlArgumentResolverTests { @BeforeEach void setUp() throws Exception { - HttpServiceProxyFactory proxyFactory = new HttpServiceProxyFactory(this.client); - proxyFactory.afterPropertiesSet(); + HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builder(this.client).build(); this.service = proxyFactory.createClient(Service.class); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java index 3ad530d4a61..c62e255028e 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java @@ -124,6 +124,15 @@ public final class WebClientAdapter implements HttpClientAdapter { } + /** + * Create a {@link WebClientAdapter} for the given {@code WebClient} instance. + * @param webClient the client to use + * @return the created adapter instance + */ + public static WebClientAdapter forClient(WebClient webClient) { + return new WebClientAdapter(webClient); + } + /** * Static method to create a {@link HttpServiceProxyFactory} configured to * use the given {@link WebClient} instance. Effectively a shortcut for: @@ -133,7 +142,11 @@ public final class WebClientAdapter implements HttpClientAdapter { * * @param webClient the client to use * @return the created {@code HttpServiceProxyFactory} instance + * @deprecated in favor of using {@link #forClient(WebClient)} and + * {@link HttpServiceProxyFactory#builder(HttpClientAdapter)} */ + @SuppressWarnings("removal") + @Deprecated(since = "6.0.0-RC1", forRemoval = true) public static HttpServiceProxyFactory createHttpServiceProxyFactory(WebClient webClient) { return new HttpServiceProxyFactory(new WebClientAdapter(webClient)); } @@ -143,18 +156,12 @@ public final class WebClientAdapter implements HttpClientAdapter { * a {@link WebClient.Builder} and uses it to create the client. * @param webClientBuilder a builder to create the client to use with * @return the created {@code HttpServiceProxyFactory} instance + * @deprecated in favor of using {@link #forClient(WebClient)} and + * {@link HttpServiceProxyFactory#builder(HttpClientAdapter)} */ + @Deprecated(since = "6.0.0-RC1", forRemoval = true) public static HttpServiceProxyFactory createHttpServiceProxyFactory(WebClient.Builder webClientBuilder) { return createHttpServiceProxyFactory(webClientBuilder.build()); } - /** - * Create a {@link WebClientAdapter} for the given {@code WebClient} instance. - * @param webClient the client to use - * @return the created adapter instance - */ - public static WebClientAdapter forClient(WebClient webClient) { - return new WebClientAdapter(webClient); - } - } 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 a05862eed4c..9934cc7d0eb 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 @@ -105,10 +105,11 @@ public class WebClientHttpServiceProxyTests { return initHttpService(webClient); } - private TestHttpService initHttpService(WebClient webClient) throws Exception { - HttpServiceProxyFactory factory = WebClientAdapter.createHttpServiceProxyFactory(webClient); - factory.afterPropertiesSet(); - return factory.createClient(TestHttpService.class); + private TestHttpService initHttpService(WebClient webClient) { + return HttpServiceProxyFactory.builder() + .clientAdapter(WebClientAdapter.forClient(webClient)) + .build() + .createClient(TestHttpService.class); } private void prepareResponse(Consumer consumer) { diff --git a/src/docs/asciidoc/integration.adoc b/src/docs/asciidoc/integration.adoc index fb8990461da..13e167bb498 100644 --- a/src/docs/asciidoc/integration.adoc +++ b/src/docs/asciidoc/integration.adoc @@ -390,8 +390,7 @@ Two, create a proxy that will perform the declared HTTP exchanges: [source,java,indent=0,subs="verbatim,quotes"] ---- WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build(); - HttpServiceProxyFactory factory = WebClientAdapter.createHttpServiceProxyFactory(client); - factory.afterPropertiesSet(); + HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build(); RepositoryService service = factory.createClient(RepositoryService.class); ----