From c9df1c551a56ac4344974d63f67c60f7608f6afc Mon Sep 17 00:00:00 2001 From: dnosan Date: Sat, 31 Mar 2018 15:07:42 +0300 Subject: [PATCH 1/3] Add auto-configuration for WebServiceTemplate See gh-12707 --- .../WebServiceTemplateAutoConfiguration.java | 67 + .../webservices/client/package-info.java | 20 + .../main/resources/META-INF/spring.factories | 3 +- ...ServiceTemplateAutoConfigurationTests.java | 150 +++ .../main/asciidoc/spring-boot-features.adoc | 30 +- spring-boot-project/spring-boot/pom.xml | 10 + .../client/WebServiceTemplateBuilder.java | 1106 +++++++++++++++++ .../client/WebServiceTemplateCustomizer.java | 34 + .../boot/webservices/client/package-info.java | 21 + ...plateBuilderCustomsMessageSenderTests.java | 93 ++ ...mponentsClientHttpRequestFactoryTests.java | 55 + ...ilderHttpComponentsMessageSenderTests.java | 67 + ...erHttpUrlConnectionMessageSenderTests.java | 70 ++ ...rOkHttp3ClientHttpRequestFactoryTests.java | 82 ++ ...erSimpleClientHttpRequestFactoryTests.java | 52 + .../WebServiceTemplateBuilderTests.java | 520 ++++++++ 16 files changed, 2378 insertions(+), 2 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java new file mode 100644 index 0000000000..e12ee5b8bc --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java @@ -0,0 +1,67 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.webservices.client; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.webservices.client.WebServiceTemplateBuilder; +import org.springframework.boot.webservices.client.WebServiceTemplateCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; +import org.springframework.util.CollectionUtils; +import org.springframework.ws.client.core.WebServiceTemplate; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for {@link WebServiceTemplate}. + * + * @author Dmytro Nosan + */ +@Configuration +@ConditionalOnClass({ WebServiceTemplateBuilder.class, WebServiceTemplate.class, + Unmarshaller.class, Marshaller.class }) +public class WebServiceTemplateAutoConfiguration { + + private final ObjectProvider> webServiceTemplateCustomizers; + + public WebServiceTemplateAutoConfiguration( + ObjectProvider> webServiceTemplateCustomizers) { + this.webServiceTemplateCustomizers = webServiceTemplateCustomizers; + } + + @Bean + @ConditionalOnMissingBean + public WebServiceTemplateBuilder webServiceTemplateBuilder() { + WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + List customizers = this.webServiceTemplateCustomizers + .getIfAvailable(); + if (!CollectionUtils.isEmpty(customizers)) { + customizers = new ArrayList<>(customizers); + AnnotationAwareOrderComparator.sort(customizers); + builder = builder.setCustomizers(customizers); + } + return builder; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/package-info.java new file mode 100644 index 0000000000..5677addf45 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Auto-configuration for Spring Web Services Clients. + */ +package org.springframework.boot.autoconfigure.webservices.client; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 8abd511201..69b1f0e790 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -126,7 +126,8 @@ org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\ -org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration +org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\ +org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration # Failure analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java new file mode 100644 index 0000000000..d60b88ca65 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java @@ -0,0 +1,150 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.webservices.client; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.webservices.client.WebServiceTemplateBuilder; +import org.springframework.boot.webservices.client.WebServiceTemplateCustomizer; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.oxm.jaxb.Jaxb2Marshaller; +import org.springframework.ws.client.core.WebServiceTemplate; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateAutoConfiguration + * WebServiceTemplateAutoConfiguration}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateAutoConfigurationTests { + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void webServiceTemplateShouldNotHaveMarshallerAndUnmarshaller() { + load(WebServiceTemplateConfig.class); + WebServiceTemplate webServiceTemplate = this.context + .getBean(WebServiceTemplate.class); + assertThat(webServiceTemplate.getUnmarshaller()).isNull(); + assertThat(webServiceTemplate.getMarshaller()).isNull(); + } + + @Test + public void webServiceTemplateShouldUserCustomBuilder() { + load(CustomWebServiceTemplateBuilderConfig.class, WebServiceTemplateConfig.class); + WebServiceTemplate webServiceTemplate = this.context + .getBean(WebServiceTemplate.class); + assertThat(webServiceTemplate.getMarshaller()).isNotNull(); + } + + @Test + public void webServiceTemplateShouldApplyCustomizer() { + load(WebServiceTemplateCustomizerConfig.class, WebServiceTemplateConfig.class); + WebServiceTemplate webServiceTemplate = this.context + .getBean(WebServiceTemplate.class); + assertThat(webServiceTemplate.getUnmarshaller()).isNotNull(); + } + + @Test + public void builderShouldBeFreshForEachUse() { + load(DirtyWebServiceTemplateConfig.class); + } + + private void load(Class... config) { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(config); + ctx.register(WebServiceTemplateAutoConfiguration.class); + ctx.refresh(); + this.context = ctx; + } + + @Configuration + static class WebServiceTemplateConfig { + + @Bean + public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) { + return builder.build(); + } + + } + + @Configuration + static class DirtyWebServiceTemplateConfig { + + @Bean + public WebServiceTemplate webServiceTemplateOne( + WebServiceTemplateBuilder builder) { + try { + return builder.build(); + } + finally { + breakBuilderOnNextCall(builder); + } + } + + @Bean + public WebServiceTemplate webServiceTemplateTwo( + WebServiceTemplateBuilder builder) { + try { + return builder.build(); + } + finally { + breakBuilderOnNextCall(builder); + } + } + + private void breakBuilderOnNextCall(WebServiceTemplateBuilder builder) { + builder.addCustomizers((webServiceTemplate) -> { + throw new IllegalStateException(); + }); + } + + } + + @Configuration + static class CustomWebServiceTemplateBuilderConfig { + + @Bean + public WebServiceTemplateBuilder webServiceTemplateBuilder() { + return new WebServiceTemplateBuilder().setMarshaller(new Jaxb2Marshaller()); + } + + } + + @Configuration + static class WebServiceTemplateCustomizerConfig { + + @Bean + public WebServiceTemplateCustomizer webServiceTemplateCustomizer() { + return (ws) -> ws.setUnmarshaller(new Jaxb2Marshaller()); + } + + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index d0677cafd9..beb46654bf 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5634,7 +5634,6 @@ The following code shows a typical example: ---- - [[boot-features-webclient-customization]] === WebClient Customization There are three main approaches to `WebClient` customization, depending on how broadly you @@ -5653,6 +5652,35 @@ the point of injection. Finally, you can fall back to the original API and use `WebClient.create()`. In that case, no auto-configuration or `WebClientCustomizer` is applied. +[[boot-features-webservicetemplate]] +== Calling Web Services with `WebServiceTemplate` +If you need to call remote WEB services from your application, you can use the Spring +Framework's {spring-webservices-reference}#client-web-service-template[`WebServiceTemplate`] class. Since +`WebServiceTemplate` instances often need to be customized before being used, Spring Boot does +not provide any single auto-configured `WebServiceTemplate` bean. It does, however, +auto-configure a `WebServiceTemplateBuilder`, which can be used to create `WebServiceTemplate` +instances when needed. + +The following code shows a typical example: + +[source,java,indent=0] +---- + @Service + public class MyService { + + private final WebServiceTemplate webServiceTemplate; + + public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) { + this.webServiceTemplate = webServiceTemplateBuilder.build(); + } + + public DetailsResp someCall(DetailsReq detailsReq) { + return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION)); + + } + + } +---- [[boot-features-validation]] diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index aff395bf3f..dcbecba691 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -245,6 +245,16 @@ spring-orm true + + org.springframework.ws + spring-ws-core + true + + + org.springframework + spring-oxm + true + org.springframework spring-test diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java new file mode 100644 index 0000000000..4a185900d5 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java @@ -0,0 +1,1106 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import java.lang.reflect.Field; +import java.net.URI; +import java.time.Duration; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; + +import javax.xml.transform.TransformerFactory; + +import org.springframework.beans.BeanUtils; +import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.ws.WebServiceMessageFactory; +import org.springframework.ws.client.core.FaultMessageResolver; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.client.support.destination.DestinationProvider; +import org.springframework.ws.client.support.interceptor.ClientInterceptor; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; +import org.springframework.ws.transport.http.HttpComponentsMessageSender; +import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; + +/** + * Builder that can be used to configure and create a + * {@link org.springframework.ws.client.core.WebServiceTemplate}. By default the built + * {@link org.springframework.ws.client.core.WebServiceTemplate} will attempt to use the + * most suitable {@link org.springframework.ws.transport.WebServiceMessageSender}, call + * {@link #detectWebServiceMessageSender(boolean) detectWebServiceMessageSender(false)} if + * you prefer to keep the default. In a typical auto-configured Spring Boot application + * this builder is available as a bean and can be injected whenever a + * {@link WebServiceTemplate} is needed. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilder { + + private static final Map> MESSAGE_SENDER_FACTORY_CLASSES; + + static { + Map> candidates = new LinkedHashMap<>(); + candidates.put("org.apache.http.client.HttpClient", + HttpComponentsMessageSenderFactory.class); + candidates.put("org.springframework.http.client.ClientHttpRequestFactory", + ClientHttpRequestMessageSenderFactory.class); + MESSAGE_SENDER_FACTORY_CLASSES = Collections.unmodifiableMap(candidates); + } + + private final Set interceptors; + + private final Set internalCustomizers; + + private final Set customizers; + + private final Set> webServiceMessageSenderSuppliers; + + private final Set webServiceMessageSenderCustomizers; + + private final Marshaller marshaller; + + private final Unmarshaller unmarshaller; + + private final DestinationProvider destinationProvider; + + private final Class transformerFactoryClass; + + private final WebServiceMessageFactory messageFactory; + + private final boolean detectWebServiceMessageSender; + + public WebServiceTemplateBuilder(WebServiceTemplateCustomizer... customizers) { + this(Collections.emptySet(), Collections.emptySet(), + append(Collections.emptySet(), customizers), + Collections.emptySet(), Collections.emptySet(), null, null, null, null, + null, true); + } + + private WebServiceTemplateBuilder(Set interceptors, + Set internalCustomizers, + Set customizers, + Set> webServiceMessageSenderSuppliers, + Set webServiceMessageSenderCustomizers, + Marshaller marshaller, Unmarshaller unmarshaller, + DestinationProvider destinationProvider, + Class transformerFactoryClass, + WebServiceMessageFactory messageFactory, + boolean detectWebServiceMessageSender) { + this.interceptors = interceptors; + this.internalCustomizers = internalCustomizers; + this.customizers = customizers; + this.webServiceMessageSenderSuppliers = webServiceMessageSenderSuppliers; + this.webServiceMessageSenderCustomizers = webServiceMessageSenderCustomizers; + this.marshaller = marshaller; + this.unmarshaller = unmarshaller; + this.destinationProvider = destinationProvider; + this.transformerFactoryClass = transformerFactoryClass; + this.messageFactory = messageFactory; + this.detectWebServiceMessageSender = detectWebServiceMessageSender; + } + + /** + * Set {@link ClientInterceptor ClientInterceptors} that should be used with the + * {@link WebServiceTemplate}. Interceptors are applied in the order that they were + * added after builder configuration has been applied. + * + * Note! Override existing interceptors + * @param interceptors the interceptors to set + * @return a new builder instance + * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + */ + public WebServiceTemplateBuilder setInterceptors(ClientInterceptor... interceptors) { + Assert.notNull(interceptors, "interceptors must not be null"); + return setInterceptors(Arrays.asList(interceptors)); + } + + /** + * Set {@link ClientInterceptor ClientInterceptors} that should be used with the + * {@link WebServiceTemplate}. Interceptors are applied in the order that they were + * added after builder configuration has been applied. + * + * Note! Override existing interceptors + * @param interceptors the interceptors to set + * @return a new builder instance + * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + */ + public WebServiceTemplateBuilder setInterceptors( + Collection interceptors) { + Assert.notNull(interceptors, "interceptors must not be null"); + return new WebServiceTemplateBuilder( + append(Collections.emptySet(), interceptors), + this.internalCustomizers, this.customizers, + this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Add additional {@link ClientInterceptor ClientInterceptors} that should be used + * with the {@link WebServiceTemplate}. Interceptors are applied in the order that + * they were added after builder configuration has been applied. + * @param interceptors the interceptors to add + * @return a new builder instance + * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + */ + public WebServiceTemplateBuilder addInterceptors(ClientInterceptor... interceptors) { + Assert.notNull(interceptors, "interceptors must not be null"); + return addInterceptors(Arrays.asList(interceptors)); + } + + /** + * Add additional {@link ClientInterceptor ClientInterceptors} that should be used + * with the {@link WebServiceTemplate}. Interceptors are applied in the order that + * they were added after builder configuration has been applied. + * @param interceptors the interceptors to add + * @return a new builder instance + * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + */ + public WebServiceTemplateBuilder addInterceptors( + Collection interceptors) { + Assert.notNull(interceptors, "interceptors must not be null"); + return new WebServiceTemplateBuilder(append(this.interceptors, interceptors), + this.internalCustomizers, this.customizers, + this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should + * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order + * that they were added after builder configuration has been applied. + * + * Note! Override existing customizers + * @param customizers the customizers to set + * @return a new builder instance + */ + + public WebServiceTemplateBuilder setCustomizers( + Collection customizers) { + Assert.notNull(customizers, "customizers must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + append(Collections.emptySet(), customizers), + this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should + * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order + * that they were added after builder configuration has been applied. + * + * Note! Override existing customizers + * @param customizers the customizers to set + * @return a new builder instance + */ + public WebServiceTemplateBuilder setCustomizers( + WebServiceTemplateCustomizer... customizers) { + Assert.notNull(customizers, "customizers must not be null"); + return setCustomizers(Arrays.asList(customizers)); + } + + /** + * Add additional {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} + * that should be applied to the {@link WebServiceTemplate}. Customizers are applied + * in the order that they were added after builder configuration has been applied. + * @param customizers the customizers to add + * @return a new builder instance + */ + public WebServiceTemplateBuilder addCustomizers( + WebServiceTemplateCustomizer... customizers) { + Assert.notNull(customizers, "customizers must not be null"); + return addCustomizers(Arrays.asList(customizers)); + } + + /** + * Add additional {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} + * that should be applied to the {@link WebServiceTemplate}. Customizers are applied + * in the order that they were added after builder configuration has been applied. + * @param customizers the customizers to add + * @return a new builder instance + */ + + public WebServiceTemplateBuilder addCustomizers( + Collection customizers) { + Assert.notNull(customizers, "customizers must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + append(this.customizers, customizers), + this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Sets the {@code Suppliers} of {@link WebServiceMessageSender} that should be called + * each time when {@link #configure(WebServiceTemplate)} method is called. + * + * Note! Override existing WebServiceMessageSender {@code suppliers} + * @param webServiceMessageSenderSuppliers Suppliers for the messageSenders + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + */ + + public WebServiceTemplateBuilder setWebServiceMessageSenders( + Collection> webServiceMessageSenderSuppliers) { + Assert.notNull(webServiceMessageSenderSuppliers, + "webServiceMessageSenderSuppliers must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, + append(Collections + .>emptySet(), + webServiceMessageSenderSuppliers), + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Add additional {@code Suppliers} of {@link WebServiceMessageSender} that should be + * called each time when {@link #configure(WebServiceTemplate)} method is called. + * @param webServiceMessageSenderSuppliers Suppliers for the messageSenders + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + */ + public WebServiceTemplateBuilder addWebServiceMessageSenders( + Collection> webServiceMessageSenderSuppliers) { + Assert.notNull(webServiceMessageSenderSuppliers, + "webServiceMessageSenderSuppliers must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, + append(this.webServiceMessageSenderSuppliers, + webServiceMessageSenderSuppliers), + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setCheckConnectionForFault(boolean) + * setCheckConnectionForFault} on the underlying. + * @param checkConnectionForFault Specify whether checkConnectionForFault should be + * enabled or not. + * @return a new builder instance. + **/ + public WebServiceTemplateBuilder setCheckConnectionForFault( + boolean checkConnectionForFault) { + return new WebServiceTemplateBuilder(this.interceptors, + append(this.internalCustomizers, + new CheckConnectionFaultCustomizer(checkConnectionForFault)), + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setCheckConnectionForError(boolean) + * setCheckConnectionForError} on the underlying. + * @param checkConnectionForError Specify whether checkConnectionForError should be + * enabled or not. + * @return a new builder instance. + **/ + + public WebServiceTemplateBuilder setCheckConnectionForError( + boolean checkConnectionForError) { + return new WebServiceTemplateBuilder(this.interceptors, + append(this.internalCustomizers, + new CheckConnectionForErrorCustomizer(checkConnectionForError)), + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Sets the {@code Supplier} of {@link WebServiceMessageSender} that should be called + * each time when {@link #configure(WebServiceTemplate)} method is called. + * + * Note! Override existing WebServiceMessageSender {@code suppliers} + * @param webServiceMessageSenderSupplier Supplier for the messageSender + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see #setWebServiceMessageSenders(Collection) + */ + + public WebServiceTemplateBuilder setWebServiceMessageSender( + Supplier webServiceMessageSenderSupplier) { + Assert.notNull(webServiceMessageSenderSupplier, + "webServiceMessageSenderSupplier must not be null"); + return setWebServiceMessageSenders( + Collections.singleton(webServiceMessageSenderSupplier)); + } + + /** + * Add additional {@code Supplier} of {@link WebServiceMessageSender} that should be + * called each time when {@link #configure(WebServiceTemplate)} method is called. + * @param webServiceMessageSenderSupplier Supplier for the messageSender + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see #addWebServiceMessageSenders(Collection) + */ + public WebServiceTemplateBuilder addWebServiceMessageSender( + Supplier webServiceMessageSenderSupplier) { + Assert.notNull(webServiceMessageSenderSupplier, + "webServiceMessageSenderSupplier must not be null"); + return addWebServiceMessageSenders( + Collections.singleton(webServiceMessageSenderSupplier)); + } + + /** + * Sets the {@code Class} of {@link WebServiceMessageSender} that should be created + * each time when {@link #configure(WebServiceTemplate)} method is called. + * + * Note! Override existing WebServiceMessageSender {@code suppliers} + * @param webServiceMessageSenderClass {@code Class} of + * {@link WebServiceMessageSender} + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see #setWebServiceMessageSender(Supplier) + * @see BeanUtils#instantiateClass(Class) + */ + + public WebServiceTemplateBuilder setWebServiceMessageSender( + Class webServiceMessageSenderClass) { + Assert.notNull(webServiceMessageSenderClass, + "webServiceMessageSenderClass must not be null"); + return setWebServiceMessageSender( + supplier(webServiceMessageSenderClass, BeanUtils::instantiateClass)); + } + + /** + * Add additional {@code Class} of {@link WebServiceMessageSender} that should be + * created each time when {@link #configure(WebServiceTemplate)} method is called. + * @param webServiceMessageSenderClass {@code Class} of + * {@link WebServiceMessageSender} + * @return a new builder instance. + * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see #addWebServiceMessageSender(Supplier) + * @see BeanUtils#instantiateClass(Class) + */ + public WebServiceTemplateBuilder addWebServiceMessageSender( + Class webServiceMessageSenderClass) { + Assert.notNull(webServiceMessageSenderClass, + "webServiceMessageSenderClass must not be null"); + return addWebServiceMessageSender( + supplier(webServiceMessageSenderClass, BeanUtils::instantiateClass)); + } + + /** + * Sets the message factory used for creating messages. + * @param messageFactory instance of WebServiceMessageFactory + * @return a new builder instance. + * @see WebServiceTemplate#setMessageFactory(WebServiceMessageFactory) + **/ + + public WebServiceTemplateBuilder setWebServiceMessageFactory( + WebServiceMessageFactory messageFactory) { + Assert.notNull(messageFactory, "messageFactory must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setUnmarshaller(Unmarshaller) unmarshaller} on the + * underlying. + * @param unmarshaller message unmarshaller + * @return a new builder instance. + * @see WebServiceTemplate#setUnmarshaller(Unmarshaller) + **/ + public WebServiceTemplateBuilder setUnmarshaller(Unmarshaller unmarshaller) { + Assert.notNull(unmarshaller, "unmarshaller must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setMarshaller(Marshaller) marshaller} on the + * underlying. + * @param marshaller message marshaller + * @return a new builder instance. + * @see WebServiceTemplate#setMarshaller(Marshaller) + **/ + public WebServiceTemplateBuilder setMarshaller(Marshaller marshaller) { + Assert.notNull(marshaller, "marshaller must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Sets the connection timeout in milliseconds on the underlying. + * @param connectionTimeout the connection timeout in milliseconds + * @return a new builder instance. + * @throws java.lang.IllegalStateException if the underlying source doesn't support a + * connection timeout. + */ + public WebServiceTemplateBuilder setConnectionTimeout(int connectionTimeout) { + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + append(this.webServiceMessageSenderCustomizers, + new ConnectionTimeoutWebServiceMessageSenderCustomizer( + connectionTimeout)), + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory, + this.detectWebServiceMessageSender); + } + + /** + * Sets the read timeout in milliseconds on the underlying. + * @param readTimeout the read timeout in milliseconds + * @return a new builder instance. + * @throws java.lang.IllegalStateException if the underlying source doesn't support a + * read timeout. + */ + public WebServiceTemplateBuilder setReadTimeout(int readTimeout) { + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + append(this.webServiceMessageSenderCustomizers, + new ReadTimeoutWebServiceMessageSenderCustomizer(readTimeout)), + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory, + this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setFaultMessageResolver(FaultMessageResolver) + * faultMessageResolver} on the underlying. + * @param faultMessageResolver faultMessageResolver may be set to null to disable + * fault handling. + * @return a new builder instance. + **/ + public WebServiceTemplateBuilder setFaultMessageResolver( + FaultMessageResolver faultMessageResolver) { + return new WebServiceTemplateBuilder(this.interceptors, + append(this.internalCustomizers, + new FaultMessageResolverCustomizer(faultMessageResolver)), + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set {@link WebServiceTemplate#setTransformerFactoryClass(Class) + * setTransformerFactoryClass} on the underlying. + * @param transformerFactoryClass boolean value + * @return a new builder instance. + **/ + + public WebServiceTemplateBuilder setTransformerFactoryClass( + Class transformerFactoryClass) { + Assert.notNull(transformerFactoryClass, + "transformerFactoryClass must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set the default URI to be used on operations that do not have a URI parameter. + * + * Note!Typically, either this property is set, or + * {@link #setDestinationProvider(DestinationProvider)}, but not both. + * @param defaultUri the destination provider URI to be used on operations that do not + * have a URI parameter. + * @return a new builder instance. + */ + public WebServiceTemplateBuilder setDefaultUri(String defaultUri) { + Assert.hasText(defaultUri, "defaultUri must not be empty"); + return setDestinationProvider(() -> URI.create(defaultUri)); + } + + /** + * Set {@link WebServiceTemplate#setDestinationProvider(DestinationProvider) + * destinationProvider} on the underlying. + * + * Note!Typically, either this property is set, or + * {@link #setDefaultUri(String)}, but not both. + * @param destinationProvider the destination provider URI to be used on operations + * that do not have a URI parameter. + * @return a new builder instance. + */ + public WebServiceTemplateBuilder setDestinationProvider( + DestinationProvider destinationProvider) { + Assert.notNull(destinationProvider, "destinationProvider must not be null"); + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, destinationProvider, this.transformerFactoryClass, + this.messageFactory, this.detectWebServiceMessageSender); + } + + /** + * Set if the {@link WebServiceMessageSender} should be detected based on the + * classpath. Default is {@code true}. + * @param detectWebServiceMessageSender if the {@link WebServiceMessageSender} should + * be detected + * @return a new builder instance + */ + public WebServiceTemplateBuilder detectWebServiceMessageSender( + boolean detectWebServiceMessageSender) { + return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + this.customizers, this.webServiceMessageSenderSuppliers, + this.webServiceMessageSenderCustomizers, this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory, detectWebServiceMessageSender); + } + + /** + * Build a new {@link WebServiceTemplate} instance and configure it using this + * builder. + * @return a configured {@link WebServiceTemplate} instance. + * @see #build(Class) + * @see #configure(WebServiceTemplate) + */ + public WebServiceTemplate build() { + return build(WebServiceTemplate.class); + } + + /** + * Build a new {@link WebServiceTemplate} instance of the specified type and configure + * it using this builder. + * @param the type of web service template + * @param webServiceTemplateClass the template type to create + * @return a configured {@link WebServiceTemplate} instance. + * @see WebServiceTemplateBuilder#build() + * @see #configure(WebServiceTemplate) + */ + + public T build(Class webServiceTemplateClass) { + Assert.notNull(webServiceTemplateClass, + "webServiceTemplateClass must not be null"); + return configure(BeanUtils.instantiateClass(webServiceTemplateClass)); + } + + /** + * Configure the provided {@link WebServiceTemplate} instance using this builder. + * @param the type of web service template + * @param webServiceTemplate the {@link WebServiceTemplate} to configure + * @return the web service template instance + * @see #build() + * @see #build(Class) + */ + public T configure(T webServiceTemplate) { + Assert.notNull(webServiceTemplate, "webServiceTemplate must not be null"); + + configureSenders(webServiceTemplate); + + if (!CollectionUtils.isEmpty(this.internalCustomizers)) { + for (WebServiceTemplateCustomizer internalCustomizer : this.internalCustomizers) { + internalCustomizer.customize(webServiceTemplate); + } + } + + if (this.marshaller != null) { + webServiceTemplate.setMarshaller(this.marshaller); + } + + if (this.unmarshaller != null) { + webServiceTemplate.setUnmarshaller(this.unmarshaller); + } + + if (this.destinationProvider != null) { + webServiceTemplate.setDestinationProvider(this.destinationProvider); + } + + if (this.transformerFactoryClass != null) { + webServiceTemplate.setTransformerFactoryClass(this.transformerFactoryClass); + } + + if (this.messageFactory != null) { + webServiceTemplate.setMessageFactory(this.messageFactory); + } + + if (!CollectionUtils.isEmpty(this.customizers)) { + for (WebServiceTemplateCustomizer customizer : this.customizers) { + customizer.customize(webServiceTemplate); + } + } + + if (!CollectionUtils.isEmpty(this.interceptors)) { + webServiceTemplate.setInterceptors( + append(this.interceptors, webServiceTemplate.getInterceptors()) + .toArray(new ClientInterceptor[0])); + } + + return webServiceTemplate; + } + + private void configureSenders(T webServiceTemplate) { + + if (!CollectionUtils.isEmpty(this.webServiceMessageSenderSuppliers)) { + Set webServiceMessageSenders = new LinkedHashSet<>(); + for (Supplier webServiceMessageSenderSupplier : this.webServiceMessageSenderSuppliers) { + webServiceMessageSenders.add(webServiceMessageSenderSupplier.get()); + } + webServiceTemplate.setMessageSenders( + webServiceMessageSenders.toArray(new WebServiceMessageSender[0])); + } + else if (this.detectWebServiceMessageSender) { + webServiceTemplate.setMessageSenders( + new WebServiceMessageSender[] { detectMessageSender() }); + } + + if (!CollectionUtils.isEmpty(this.webServiceMessageSenderCustomizers)) { + if (!ObjectUtils.isEmpty(webServiceTemplate.getMessageSenders())) { + for (WebServiceMessageSender webServiceMessageSender : webServiceTemplate + .getMessageSenders()) { + for (WebServiceMessageSenderCustomizer webServiceMessageSenderCustomizer : this.webServiceMessageSenderCustomizers) { + webServiceMessageSenderCustomizer + .customize(webServiceMessageSender); + } + } + } + } + } + + private WebServiceMessageSender detectMessageSender() { + ClassLoader classLoader = getClass().getClassLoader(); + for (Map.Entry> candidate : MESSAGE_SENDER_FACTORY_CLASSES + .entrySet()) { + if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { + WebServiceMessageSenderFactory webServiceMessageSenderFactory = BeanUtils + .instantiateClass(candidate.getValue()); + Optional webServiceMessageSender = webServiceMessageSenderFactory + .create(); + if (webServiceMessageSender.isPresent()) { + return webServiceMessageSender.get(); + } + } + } + return new HttpUrlConnectionMessageSender(); + } + + private static Supplier supplier(T value, Function mapper) { + return () -> mapper.apply(value); + } + + private static Set append(Set set, T[] additions) { + return append(set, additions != null + ? new LinkedHashSet<>(Arrays.asList(additions)) : Collections.emptySet()); + } + + private static Set append(Set set, T addition) { + Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); + result.add(addition); + return Collections.unmodifiableSet(result); + } + + private static Set append(Set set, Collection additions) { + Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); + result.addAll(additions != null ? additions : Collections.emptyList()); + return Collections.unmodifiableSet(result); + } + + private interface WebServiceMessageSenderFactory { + + Optional create(); + + } + + private interface WebServiceMessageSenderCustomizer { + + void customize(WebServiceMessageSender webServiceMessageSender); + + } + + private static final class ClientHttpRequestMessageSenderFactory + implements WebServiceMessageSenderFactory { + + private static final Map REQUEST_FACTORY_CANDIDATES; + + static { + Map candidates = new LinkedHashMap<>(); + candidates.put("okhttp3.OkHttpClient", + "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"); + REQUEST_FACTORY_CANDIDATES = Collections.unmodifiableMap(candidates); + } + + @Override + public Optional create() { + ClassLoader classLoader = getClass().getClassLoader(); + for (Map.Entry candidate : REQUEST_FACTORY_CANDIDATES + .entrySet()) { + if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { + Class factoryClass = ClassUtils + .resolveClassName(candidate.getValue(), classLoader); + ClientHttpRequestFactory clientHttpRequestFactory = (ClientHttpRequestFactory) BeanUtils + .instantiateClass(factoryClass); + return Optional.of( + new ClientHttpRequestMessageSender(clientHttpRequestFactory)); + } + } + return Optional.empty(); + } + + } + + private static final class HttpComponentsMessageSenderFactory + implements WebServiceMessageSenderFactory { + + @Override + public Optional create() { + return Optional.of(new HttpComponentsMessageSender()); + } + + } + + /** + * {@link WebServiceTemplateCustomizer} to set + * {@link WebServiceTemplate#checkConnectionForFault checkConnectionForFault }. + */ + private static final class CheckConnectionFaultCustomizer + implements WebServiceTemplateCustomizer { + + private final boolean checkConnectionFault; + + private CheckConnectionFaultCustomizer(boolean checkConnectionFault) { + this.checkConnectionFault = checkConnectionFault; + } + + @Override + public void customize(WebServiceTemplate webServiceTemplate) { + webServiceTemplate.setCheckConnectionForFault(this.checkConnectionFault); + } + + } + + /** + * {@link WebServiceTemplateCustomizer} to set + * {@link WebServiceTemplate#checkConnectionForError checkConnectionForError }. + */ + private static final class CheckConnectionForErrorCustomizer + implements WebServiceTemplateCustomizer { + + private final boolean checkConnectionForError; + + private CheckConnectionForErrorCustomizer(boolean checkConnectionForError) { + this.checkConnectionForError = checkConnectionForError; + } + + @Override + public void customize(WebServiceTemplate webServiceTemplate) { + webServiceTemplate.setCheckConnectionForError(this.checkConnectionForError); + } + + } + + /** + * {@link WebServiceTemplateCustomizer} to set + * {@link WebServiceTemplate#faultMessageResolver faultMessageResolver }. + */ + private static final class FaultMessageResolverCustomizer + implements WebServiceTemplateCustomizer { + + private final FaultMessageResolver faultMessageResolver; + + private FaultMessageResolverCustomizer( + FaultMessageResolver faultMessageResolver) { + this.faultMessageResolver = faultMessageResolver; + } + + @Override + public void customize(WebServiceTemplate webServiceTemplate) { + webServiceTemplate.setFaultMessageResolver(this.faultMessageResolver); + } + + } + + /** + * {@link WebServiceMessageSenderCustomizer} to set connection timeout. + */ + private static final class ConnectionTimeoutWebServiceMessageSenderCustomizer + extends TimeoutWebServiceMessageSenderCustomizer { + + private ConnectionTimeoutWebServiceMessageSenderCustomizer(int connectTimeout) { + super(connectTimeout, Timeout.CONNECTION); + } + + } + + /** + * {@link WebServiceMessageSenderCustomizer} to set read timeout. + */ + private static final class ReadTimeoutWebServiceMessageSenderCustomizer + extends TimeoutWebServiceMessageSenderCustomizer { + + private ReadTimeoutWebServiceMessageSenderCustomizer(int readTimeout) { + super(readTimeout, Timeout.READ); + } + + } + + private abstract static class TimeoutWebServiceMessageSenderCustomizer + implements WebServiceMessageSenderCustomizer { + + private static final Map>> CUSTOMIZERS; + + static { + Map>> candidates = new LinkedHashMap<>(); + candidates.put( + "org.springframework.ws.transport.http.HttpComponentsMessageSender", + HttpComponentsTimeoutCustomizer.class); + candidates.put( + "org.springframework.ws.transport.http.ClientHttpRequestMessageSender", + ClientHttpRequestTimeoutCustomizer.class); + candidates.put( + "org.springframework.ws.transport.http.HttpUrlConnectionMessageSender", + HttpUrlConnectionTimeoutCustomizer.class); + CUSTOMIZERS = Collections.unmodifiableMap(candidates); + } + + private final Timeout type; + + private final int timeout; + + TimeoutWebServiceMessageSenderCustomizer(int timeout, Timeout type) { + this.timeout = timeout; + this.type = type; + } + + @Override + public final void customize(WebServiceMessageSender webServiceMessageSender) { + ClassLoader classLoader = getClass().getClassLoader(); + customize(CUSTOMIZERS, webServiceMessageSender, this.type, this.timeout, + classLoader); + + } + + @SuppressWarnings("unchecked") + private static void customize( + Map>> customizers, + T target, Timeout type, int timeout, ClassLoader classLoader) { + for (Map.Entry>> candidate : customizers + .entrySet()) { + if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { + Class candidateClass = ClassUtils + .resolveClassName(candidate.getKey(), classLoader); + if (ClassUtils.isAssignable(candidateClass, target.getClass())) { + TimeoutCustomizer timeoutCustomizer = BeanUtils + .instantiateClass(candidate.getValue()); + customize(timeoutCustomizer, target, type, timeout); + return; + } + } + } + throw new IllegalStateException("There is no way to customize '" + + target.getClass() + "' " + "with '" + type.name().toLowerCase() + + "Timeout'. Please use a custom " + "customizer."); + + } + + private static void customize(TimeoutCustomizer customizer, T target, + Timeout type, int timeout) { + if (type == Timeout.CONNECTION) { + customizer.setConnectionTimeout(target, timeout); + } + else if (type == Timeout.READ) { + customizer.setReadTimeout(target, timeout); + } + } + + interface TimeoutCustomizer { + + void setReadTimeout(T source, int timeout); + + void setConnectionTimeout(T source, int timeout); + + } + + enum Timeout { + + READ, CONNECTION + + } + + private static final class HttpComponentsTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(HttpComponentsMessageSender source, int timeout) { + source.setReadTimeout(timeout); + } + + @Override + public void setConnectionTimeout(HttpComponentsMessageSender source, + int timeout) { + source.setConnectionTimeout(timeout); + } + + } + + private static final class HttpUrlConnectionTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(HttpUrlConnectionMessageSender source, + int timeout) { + source.setReadTimeout(Duration.ofMillis(timeout)); + } + + @Override + public void setConnectionTimeout(HttpUrlConnectionMessageSender source, + int timeout) { + source.setConnectionTimeout(Duration.ofMillis(timeout)); + } + + } + + private static final class ClientHttpRequestTimeoutCustomizer + implements TimeoutCustomizer { + + private static final Map>> CUSTOMIZERS; + + static { + Map>> candidates = new LinkedHashMap<>(); + candidates.put( + "org.springframework.http.client.HttpComponentsClientHttpRequestFactory", + HttpComponentsClientHttpRequestFactoryTimeoutCustomizer.class); + candidates.put( + "org.springframework.http.client.OkHttp3ClientHttpRequestFactory", + OkHttp3ClientHttpRequestFactoryTimeoutCustomizer.class); + candidates.put( + "org.springframework.http.client.SimpleClientHttpRequestFactory", + SimpleClientHttpRequestFactoryTimeoutCustomizer.class); + CUSTOMIZERS = Collections.unmodifiableMap(candidates); + } + + @Override + public void setReadTimeout(ClientHttpRequestMessageSender source, + int timeout) { + ClassLoader classLoader = getClass().getClassLoader(); + customize(CUSTOMIZERS, getRequestFactory(source), Timeout.READ, timeout, + classLoader); + } + + @Override + public void setConnectionTimeout(ClientHttpRequestMessageSender source, + int timeout) { + ClassLoader classLoader = getClass().getClassLoader(); + customize(CUSTOMIZERS, getRequestFactory(source), Timeout.CONNECTION, + timeout, classLoader); + } + + private ClientHttpRequestFactory getRequestFactory( + ClientHttpRequestMessageSender source) { + ClientHttpRequestFactory requestFactory = source.getRequestFactory(); + if (!(requestFactory instanceof AbstractClientHttpRequestFactoryWrapper)) { + return requestFactory; + } + Field field = ReflectionUtils.findField( + AbstractClientHttpRequestFactoryWrapper.class, "requestFactory"); + Assert.notNull(field, "Field must not be null"); + ReflectionUtils.makeAccessible(field); + do { + requestFactory = (ClientHttpRequestFactory) ReflectionUtils + .getField(field, requestFactory); + } + while (requestFactory instanceof AbstractClientHttpRequestFactoryWrapper); + return requestFactory; + } + + private static final class SimpleClientHttpRequestFactoryTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(SimpleClientHttpRequestFactory source, + int timeout) { + source.setReadTimeout(timeout); + } + + @Override + public void setConnectionTimeout(SimpleClientHttpRequestFactory source, + int timeout) { + source.setConnectTimeout(timeout); + } + + } + + private static final class HttpComponentsClientHttpRequestFactoryTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(HttpComponentsClientHttpRequestFactory source, + int timeout) { + source.setReadTimeout(timeout); + } + + @Override + public void setConnectionTimeout( + HttpComponentsClientHttpRequestFactory source, int timeout) { + source.setConnectTimeout(timeout); + } + + } + + private static final class OkHttp3ClientHttpRequestFactoryTimeoutCustomizer + implements TimeoutCustomizer { + + @Override + public void setReadTimeout(OkHttp3ClientHttpRequestFactory source, + int timeout) { + source.setReadTimeout(timeout); + } + + @Override + public void setConnectionTimeout(OkHttp3ClientHttpRequestFactory source, + int timeout) { + source.setConnectTimeout(timeout); + } + + } + + } + + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java new file mode 100644 index 0000000000..f619e6f999 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import org.springframework.ws.client.core.WebServiceTemplate; + +/** + * Callback interface that can be used to customize a {@link WebServiceTemplate}. + * + * @author Dmytro Nosan + */ +public interface WebServiceTemplateCustomizer { + + /** + * Callback to customize a {@link WebServiceTemplate} instance. + * @param webServiceTemplate the template to customize + */ + void customize(WebServiceTemplate webServiceTemplate); + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java new file mode 100644 index 0000000000..5e0d4ce13f --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Web Services client utilities. + */ + +package org.springframework.boot.webservices.client; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java new file mode 100644 index 0000000000..8ae3040b95 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java @@ -0,0 +1,93 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +/** + * Tests for + * {@link org.springframework.boot.webservices.client.WebServiceTemplateBuilder}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilderCustomsMessageSenderTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void unknownSenderReadTimeout() { + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage("with 'readTimeout'. Please use a custom customizer."); + this.thrown.expectMessage("There is no way to customize"); + + this.builder.setReadTimeout(3000).setWebServiceMessageSender( + () -> Mockito.mock(WebServiceMessageSender.class)).build(); + } + + @Test + public void unknownSenderConnectionTimeout() { + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage( + "with 'connectionTimeout'. Please use a custom customizer."); + this.thrown.expectMessage("There is no way to customize"); + + this.builder.setConnectionTimeout(3000).setWebServiceMessageSender( + () -> Mockito.mock(WebServiceMessageSender.class)).build(); + } + + @Test + public void unknownRequestFactoryReadTimeout() { + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage("with 'readTimeout'. Please use a custom customizer."); + this.thrown.expectMessage("There is no way to customize"); + + this.builder.setReadTimeout(3000) + .setWebServiceMessageSender(() -> new ClientHttpRequestMessageSender( + Mockito.mock(ClientHttpRequestFactory.class))) + .build(); + } + + @Test + public void unknownRequestFactoryConnectionTimeout() { + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage( + "with 'connectionTimeout'. Please use a custom customizer."); + this.thrown.expectMessage("There is no way to customize"); + + this.builder.setConnectionTimeout(3000) + .setWebServiceMessageSender(() -> new ClientHttpRequestMessageSender( + Mockito.mock(ClientHttpRequestFactory.class))) + .build(); + } + + @Test + public void shouldBuildWithoutTimeouts() { + this.builder.setWebServiceMessageSender( + () -> Mockito.mock(WebServiceMessageSender.class)).build(); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java new file mode 100644 index 0000000000..f2cafa15c7 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import org.apache.http.client.config.RequestConfig; +import org.junit.Test; + +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void setTimeout() { + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( + new BufferingClientHttpRequestFactory(factory)); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + RequestConfig requestConfig = (RequestConfig) ReflectionTestUtils + .getField(factory, "requestConfig"); + assertThat(requestConfig).isNotNull(); + assertThat(requestConfig.getConnectTimeout()).isEqualTo(5000); + assertThat(requestConfig.getSocketTimeout()).isEqualTo(2000); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java new file mode 100644 index 0000000000..82f08a27de --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import org.apache.http.client.HttpClient; +import org.apache.http.params.HttpConnectionParams; +import org.junit.Test; + +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.http.HttpComponentsMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for + * {@link org.springframework.boot.webservices.client.WebServiceTemplateBuilder}. This + * test class check that builder will create HttpComponents by default if apache client is + * present in the classpath. + * + * @author Dmytro Nosan + */ +@SuppressWarnings("deprecation") +public class WebServiceTemplateBuilderHttpComponentsMessageSenderTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void build() { + WebServiceTemplate webServiceTemplate = new WebServiceTemplateBuilder().build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(HttpComponentsMessageSender.class); + + } + + @Test + public void setTimeout() { + HttpComponentsMessageSender sender = new HttpComponentsMessageSender(); + HttpClient httpClient = sender.getHttpClient(); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + assertThat(HttpConnectionParams.getConnectionTimeout(httpClient.getParams())) + .isEqualTo(5000); + assertThat(HttpConnectionParams.getSoTimeout(httpClient.getParams())) + .isEqualTo(2000); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java new file mode 100644 index 0000000000..3468091f6e --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import java.time.Duration; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; +import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. This test class check that builder will + * create HttpUrlConnectionMessageSender If Ok-http and Apache client are not present in + * the classpath. + * + * @author Dmytro Nosan + */ +@RunWith(ModifiedClassPathRunner.class) +@ClassPathExclusions({ "httpclient-*.jar", "okhttp-*.jar" }) +public class WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void build() { + WebServiceTemplate webServiceTemplate = this.builder.build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(HttpUrlConnectionMessageSender.class); + + } + + @Test + public void setTimeout() { + HttpUrlConnectionMessageSender sender = new HttpUrlConnectionMessageSender(); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + assertThat(ReflectionTestUtils.getField(sender, "connectionTimeout")) + .isEqualTo(Duration.ofMillis(5000)); + assertThat(ReflectionTestUtils.getField(sender, "readTimeout")) + .isEqualTo(Duration.ofMillis(2000)); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java new file mode 100644 index 0000000000..3d37a488f1 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import okhttp3.OkHttpClient; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; +import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. This test class check that builder will + * create ClientHttpRequestMessageSender (OkHttp3ClientHttpRequestFactory) if apache + * client is not present in the classpath + * + * @author Dmytro Nosan + */ +@RunWith(ModifiedClassPathRunner.class) +@ClassPathExclusions("httpclient-*.jar") +public class WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void build() { + + WebServiceTemplate webServiceTemplate = this.builder.build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(ClientHttpRequestMessageSender.class); + + ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) webServiceTemplate + .getMessageSenders()[0]; + + assertThat(sender.getRequestFactory()) + .isInstanceOf(OkHttp3ClientHttpRequestFactory.class); + + } + + @Test + public void setTimeout() { + OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(); + ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( + new BufferingClientHttpRequestFactory(factory)); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + OkHttpClient client = (OkHttpClient) ReflectionTestUtils.getField(factory, + "client"); + + assertThat(client).isNotNull(); + + assertThat(client.connectTimeoutMillis()).isEqualTo(5000); + assertThat(client.readTimeoutMillis()).isEqualTo(2000); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java new file mode 100644 index 0000000000..e2f3c0a5c3 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import org.junit.Test; + +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void setTimeout() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( + new BufferingClientHttpRequestFactory(factory)); + + this.builder.setConnectionTimeout(5000).setReadTimeout(2000) + .setWebServiceMessageSender(() -> sender).build(); + + assertThat(ReflectionTestUtils.getField(factory, "connectTimeout")) + .isEqualTo(5000); + assertThat(ReflectionTestUtils.getField(factory, "readTimeout")).isEqualTo(2000); + + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java new file mode 100644 index 0000000000..ffdffd4040 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java @@ -0,0 +1,520 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import java.net.URI; +import java.util.Collection; +import java.util.Collections; +import java.util.function.Supplier; + +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXTransformerFactory; + +import org.junit.Test; +import org.mockito.Mockito; + +import org.springframework.oxm.jaxb.Jaxb2Marshaller; +import org.springframework.ws.client.core.FaultMessageResolver; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.client.support.interceptor.ClientInterceptor; +import org.springframework.ws.soap.client.core.SoapFaultMessageResolver; +import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; +import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebServiceTemplateBuilder}. + * + * @author Dmytro Nosan + */ +public class WebServiceTemplateBuilderTests { + + private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + + @Test + public void addInterceptors() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = this.builder.addInterceptors(f1) + .addInterceptors(f2).build(); + + assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f1, + f2); + } + + @Test + public void addInterceptorsCollection() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = this.builder + .addInterceptors(Collections.singletonList(f1)) + .addInterceptors(Collections.singleton(f2)).build(); + + assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f1, + f2); + + } + + @Test + public void setInterceptors() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = this.builder.setInterceptors(f1) + .setInterceptors(f2).build(); + + assertThat(webServiceTemplate.getInterceptors()).doesNotContain(f1).contains(f2); + } + + @Test + public void setInterceptorsCollection() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = this.builder + .setInterceptors(Collections.singletonList(f1)) + .setInterceptors(Collections.singleton(f2)).build(); + + assertThat(webServiceTemplate.getInterceptors()).doesNotContain(f1).contains(f2); + + } + + @Test + public void addCustomizers() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + WebServiceTemplateCustomizer customizer = (ws) -> ws + .setMarshaller(jaxb2Marshaller); + WebServiceTemplateCustomizer customizer1 = (ws) -> ws + .setUnmarshaller(jaxb2Marshaller); + + WebServiceTemplate webServiceTemplate = this.builder.addCustomizers(customizer) + .addCustomizers(customizer1).build(); + + assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + + } + + @Test + public void addCustomizersCollection() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + WebServiceTemplateCustomizer customizer = (ws) -> ws + .setMarshaller(jaxb2Marshaller); + WebServiceTemplateCustomizer customizer1 = (ws) -> ws + .setUnmarshaller(jaxb2Marshaller); + + WebServiceTemplate webServiceTemplate = this.builder + .addCustomizers(Collections.singleton(customizer)) + .addCustomizers(Collections.singletonList(customizer1)).build(); + + assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + } + + @Test + public void setCustomizers() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + WebServiceTemplateCustomizer customizer = (ws) -> ws + .setMarshaller(jaxb2Marshaller); + WebServiceTemplateCustomizer customizer1 = (ws) -> ws + .setUnmarshaller(jaxb2Marshaller); + + WebServiceTemplate webServiceTemplate = this.builder.setCustomizers(customizer) + .setCustomizers(customizer1).build(); + + assertThat(webServiceTemplate.getMarshaller()).isNull(); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + + } + + @Test + public void setCustomizersCollection() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + WebServiceTemplateCustomizer customizer = (ws) -> ws + .setMarshaller(jaxb2Marshaller); + WebServiceTemplateCustomizer customizer1 = (ws) -> ws + .setUnmarshaller(jaxb2Marshaller); + + WebServiceTemplate webServiceTemplate = this.builder + .setCustomizers(Collections.singleton(customizer)) + .setCustomizers(Collections.singletonList(customizer1)).build(); + + assertThat(webServiceTemplate.getMarshaller()).isNull(); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); + } + + @Test + public void addWebServiceMessageSenders() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); + + WebServiceTemplate webServiceTemplate = this.builder + .addWebServiceMessageSenders(Collections.singleton(() -> sender)) + .addWebServiceMessageSenders(Collections.singletonList(() -> sender1)) + .build(); + + assertThat(webServiceTemplate.getMessageSenders()) + .containsExactlyInAnyOrder(sender, sender1); + } + + @Test + public void setWebServiceMessageSenders() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); + + WebServiceTemplate webServiceTemplate = this.builder + .setWebServiceMessageSenders(Collections.singleton(() -> sender)) + .setWebServiceMessageSenders(Collections.singletonList(() -> sender1)) + .build(); + + assertThat(webServiceTemplate.getMessageSenders()).doesNotContain(sender) + .contains(sender1); + + } + + @Test + public void addWebServiceMessageSenderClass() { + + WebServiceTemplate webServiceTemplate = this.builder + .addWebServiceMessageSender(ClientHttpRequestMessageSender.class) + .addWebServiceMessageSender(HttpUrlConnectionMessageSender.class).build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(2); + + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(ClientHttpRequestMessageSender.class); + assertThat(webServiceTemplate.getMessageSenders()[1]) + .isInstanceOf(HttpUrlConnectionMessageSender.class); + } + + @Test + public void setWebServiceMessageSenderClass() { + + WebServiceTemplate webServiceTemplate = this.builder + .setWebServiceMessageSender(ClientHttpRequestMessageSender.class) + .setWebServiceMessageSender(HttpUrlConnectionMessageSender.class).build(); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + assertThat(webServiceTemplate.getMessageSenders()[0]) + .isInstanceOf(HttpUrlConnectionMessageSender.class); + + } + + @Test + public void addWebServiceMessageSender() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); + + WebServiceTemplate webServiceTemplate = this.builder + .addWebServiceMessageSender(() -> sender) + .addWebServiceMessageSender(() -> sender1).build(); + + assertThat(webServiceTemplate.getMessageSenders()) + .containsExactlyInAnyOrder(sender, sender1); + } + + @Test + public void setWebServiceMessageSender() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); + + WebServiceTemplate webServiceTemplate = this.builder + .setWebServiceMessageSender(() -> sender) + .setWebServiceMessageSender(() -> sender1).build(); + + assertThat(webServiceTemplate.getMessageSenders()).doesNotContain(sender) + .contains(sender1); + + } + + @Test + public void setCheckConnectionForFault() { + MockWebServiceTemplate webServiceTemplate = this.builder + .setCheckConnectionForFault(false).build(MockWebServiceTemplate.class); + + assertThat(webServiceTemplate.isCheckConnectionForFault()).isFalse(); + } + + @Test + public void setCheckConnectionForError() { + + MockWebServiceTemplate webServiceTemplate = this.builder + .setCheckConnectionForError(false).build(MockWebServiceTemplate.class); + + assertThat(webServiceTemplate.isCheckConnectionForError()).isFalse(); + + } + + @Test + public void setTransformerFactoryClass() { + MockWebServiceTemplate webServiceTemplate = this.builder + .setTransformerFactoryClass(SAXTransformerFactory.class) + .build(MockWebServiceTemplate.class); + + assertThat(webServiceTemplate.getTransformerFactoryClass()) + .isEqualTo(SAXTransformerFactory.class); + + } + + @Test + public void setWebServiceMessageFactory() { + + SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(); + + WebServiceTemplate webServiceTemplate = this.builder + .setWebServiceMessageFactory(messageFactory).build(); + + assertThat(webServiceTemplate.getMessageFactory()).isEqualTo(messageFactory); + + } + + @Test + public void setMarshaller() { + Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); + + WebServiceTemplate webServiceTemplate = this.builder + .setMarshaller(jaxb2Marshaller).build(); + assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); + } + + @Test + public void setUnmarshaller() { + Jaxb2Marshaller jaxb2Unmarshaller = new Jaxb2Marshaller(); + + WebServiceTemplate webServiceTemplate = this.builder + .setUnmarshaller(jaxb2Unmarshaller).build(); + + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Unmarshaller); + } + + @Test + public void setFaultMessageResolver() { + + FaultMessageResolver faultMessageResolver = new SoapFaultMessageResolver(); + WebServiceTemplate webServiceTemplate = this.builder + .setFaultMessageResolver(faultMessageResolver).build(); + + assertThat(webServiceTemplate.getFaultMessageResolver()) + .isEqualTo(faultMessageResolver); + } + + @Test + public void setDefaultUri() { + URI uri = URI.create("http://localhost:8080"); + + WebServiceTemplate webServiceTemplate = this.builder.setDefaultUri(uri.toString()) + .build(); + + assertThat(webServiceTemplate.getDestinationProvider().getDestination()) + .isEqualTo(uri); + + } + + @Test + public void setDestinationProvider() { + URI uri = URI.create("http://localhost:8080"); + + WebServiceTemplate webServiceTemplate = this.builder + .setDestinationProvider(() -> uri).build(); + + assertThat(webServiceTemplate.getDestinationProvider().getDestination()) + .isEqualTo(uri); + + } + + @Test + public void shouldNotOverrideDefaultSender() { + WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); + WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); + webServiceTemplate.setMessageSender(sender); + + this.builder.detectWebServiceMessageSender(false).configure(webServiceTemplate); + + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1).contains(sender); + + } + + @Test + public void addInterceptorsToExistingWebServiceTemplate() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + + WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); + webServiceTemplate.setInterceptors(new ClientInterceptor[] { f1 }); + + this.builder.addInterceptors(f2).configure(webServiceTemplate); + + assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f2, + f1); + } + + @Test(expected = IllegalArgumentException.class) + public void setInterceptorsArrayNull() { + this.builder.setInterceptors((ClientInterceptor[]) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setInterceptorsCollectionNull() { + this.builder.setInterceptors((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addInterceptorsArrayNull() { + this.builder.addInterceptors((ClientInterceptor[]) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addInterceptorsCollectionNull() { + this.builder.addInterceptors((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setCustomizersArrayNull() { + this.builder.setCustomizers((WebServiceTemplateCustomizer[]) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setCustomizersCollectionNull() { + this.builder + .setCustomizers((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addCustomizersArrayNull() { + this.builder + .addCustomizers((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addCustomizersCollectionNull() { + this.builder + .addCustomizers((Collection) null) + .build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setWebServiceMessageSendersNull() { + this.builder.setWebServiceMessageSenders(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addWebServiceMessageSendersNull() { + this.builder.addWebServiceMessageSenders(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setWebServiceMessageSenderClassNull() { + this.builder.setWebServiceMessageSender( + (Class) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addWebServiceMessageSenderClassNull() { + this.builder.addWebServiceMessageSender( + (Class) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setWebServiceMessageSenderSupplierNull() { + this.builder.setWebServiceMessageSender( + (Supplier) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void addWebServiceMessageSenderSupplierNull() { + this.builder.addWebServiceMessageSender( + (Supplier) null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setWebServiceMessageFactoryNull() { + this.builder.setWebServiceMessageFactory(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setUnmarshallerNull() { + this.builder.setUnmarshaller(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setMarshallerNull() { + this.builder.setMarshaller(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setTransformerFactoryClassNull() { + this.builder.setTransformerFactoryClass(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setDefaultUriNull() { + this.builder.setDefaultUri(null).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void setDestinationProviderNull() { + this.builder.setDestinationProvider(null).build(); + } + + private static class MockWebServiceTemplate extends WebServiceTemplate { + + private boolean checkConnectionForError; + + private boolean checkConnectionForFault; + + private Class transformerFactoryClass; + + boolean isCheckConnectionForError() { + return this.checkConnectionForError; + } + + @Override + public void setCheckConnectionForError(boolean checkConnectionForError) { + this.checkConnectionForError = checkConnectionForError; + } + + boolean isCheckConnectionForFault() { + return this.checkConnectionForFault; + } + + @Override + public void setCheckConnectionForFault(boolean checkConnectionForFault) { + this.checkConnectionForFault = checkConnectionForFault; + } + + Class getTransformerFactoryClass() { + return this.transformerFactoryClass; + } + + @Override + public void setTransformerFactoryClass( + Class transformerFactoryClass) { + this.transformerFactoryClass = transformerFactoryClass; + } + + } + +} From ef9c1a8e35d82ac8465d1e37ca32938086a8d8fc Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Fri, 1 Jun 2018 11:48:43 +0200 Subject: [PATCH 2/3] Extract ClientHttpRequestFactory detection to its own class See gh-12707 --- .../ClientHttpRequestFactorySupplier.java | 65 +++++++++++++++++++ .../boot/web/client/RestTemplateBuilder.java | 31 +-------- 2 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactorySupplier.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactorySupplier.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactorySupplier.java new file mode 100644 index 0000000000..f55039f233 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactorySupplier.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.web.client; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Supplier; + +import org.springframework.beans.BeanUtils; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.util.ClassUtils; + +/** + * A supplier for {@link ClientHttpRequestFactory} that detects the preferred candidate + * based on the available implementations on the classpath. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class ClientHttpRequestFactorySupplier + implements Supplier { + + private static final Map REQUEST_FACTORY_CANDIDATES; + + static { + Map candidates = new LinkedHashMap<>(); + candidates.put("org.apache.http.client.HttpClient", + "org.springframework.http.client.HttpComponentsClientHttpRequestFactory"); + candidates.put("okhttp3.OkHttpClient", + "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"); + REQUEST_FACTORY_CANDIDATES = Collections.unmodifiableMap(candidates); + } + + @Override + public ClientHttpRequestFactory get() { + for (Map.Entry candidate : REQUEST_FACTORY_CANDIDATES + .entrySet()) { + ClassLoader classLoader = getClass().getClassLoader(); + if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { + Class factoryClass = ClassUtils.resolveClassName(candidate.getValue(), + classLoader); + return (ClientHttpRequestFactory) BeanUtils + .instantiateClass(factoryClass); + } + } + return new SimpleClientHttpRequestFactory(); + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java index 58d464deb4..5038a5ecd0 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java @@ -23,9 +23,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.Map; import java.util.Set; import java.util.function.Supplier; @@ -33,11 +31,9 @@ import org.springframework.beans.BeanUtils; import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.http.client.support.BasicAuthorizationInterceptor; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import org.springframework.web.client.ResponseErrorHandler; @@ -64,17 +60,6 @@ import org.springframework.web.util.UriTemplateHandler; */ public class RestTemplateBuilder { - private static final Map REQUEST_FACTORY_CANDIDATES; - - static { - Map candidates = new LinkedHashMap<>(); - candidates.put("org.apache.http.client.HttpClient", - "org.springframework.http.client.HttpComponentsClientHttpRequestFactory"); - candidates.put("okhttp3.OkHttpClient", - "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"); - REQUEST_FACTORY_CANDIDATES = Collections.unmodifiableMap(candidates); - } - private final boolean detectRequestFactory; private final String rootUri; @@ -561,7 +546,7 @@ public class RestTemplateBuilder { requestFactory = this.requestFactorySupplier.get(); } else if (this.detectRequestFactory) { - requestFactory = detectRequestFactory(); + requestFactory = new ClientHttpRequestFactorySupplier().get(); } if (requestFactory != null) { ClientHttpRequestFactory unwrappedRequestFactory = unwrapRequestFactoryIfNecessary( @@ -590,20 +575,6 @@ public class RestTemplateBuilder { return unwrappedRequestFactory; } - private ClientHttpRequestFactory detectRequestFactory() { - for (Map.Entry candidate : REQUEST_FACTORY_CANDIDATES - .entrySet()) { - ClassLoader classLoader = getClass().getClassLoader(); - if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { - Class factoryClass = ClassUtils.resolveClassName(candidate.getValue(), - classLoader); - return (ClientHttpRequestFactory) BeanUtils - .instantiateClass(factoryClass); - } - } - return new SimpleClientHttpRequestFactory(); - } - private Set append(Set set, T addition) { Set result = new LinkedHashSet<>(set != null ? set : Collections.emptySet()); result.add(addition); From 8bcea0d8cccc30f202a49c02ad4638244748eb97 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 31 May 2018 12:28:45 +0200 Subject: [PATCH 3/3] Polish "Add auto-configuration for WebServiceTemplate" Closes gh-1270 --- .../WebServiceTemplateAutoConfiguration.java | 6 +- ...ServiceTemplateAutoConfigurationTests.java | 106 +- .../main/asciidoc/spring-boot-features.adoc | 75 +- spring-boot-project/spring-boot/pom.xml | 10 +- .../HttpWebServiceMessageSenderBuilder.java | 124 ++ .../client/WebServiceTemplateBuilder.java | 1021 +++++------------ .../client/WebServiceTemplateCustomizer.java | 1 + .../boot/webservices/client/package-info.java | 1 - ...SenderBuilderOkHttp3IntegrationTests.java} | 55 +- ...geSenderBuilderSimpleIntegrationTests.java | 71 ++ ...tpWebServiceMessageSenderBuilderTests.java | 84 ++ ...plateBuilderCustomsMessageSenderTests.java | 93 -- ...mponentsClientHttpRequestFactoryTests.java | 55 - ...ilderHttpComponentsMessageSenderTests.java | 67 -- ...erHttpUrlConnectionMessageSenderTests.java | 70 -- ...erSimpleClientHttpRequestFactoryTests.java | 52 - .../WebServiceTemplateBuilderTests.java | 668 +++++------ 17 files changed, 972 insertions(+), 1587 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java rename spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/{WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java => HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java} (55%) create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java delete mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java index e12ee5b8bc..d7a2edfeb2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfiguration.java @@ -37,10 +37,10 @@ import org.springframework.ws.client.core.WebServiceTemplate; * {@link EnableAutoConfiguration Auto-configuration} for {@link WebServiceTemplate}. * * @author Dmytro Nosan + * @since 2.1.0 */ @Configuration -@ConditionalOnClass({ WebServiceTemplateBuilder.class, WebServiceTemplate.class, - Unmarshaller.class, Marshaller.class }) +@ConditionalOnClass({ WebServiceTemplate.class, Unmarshaller.class, Marshaller.class }) public class WebServiceTemplateAutoConfiguration { private final ObjectProvider> webServiceTemplateCustomizers; @@ -59,7 +59,7 @@ public class WebServiceTemplateAutoConfiguration { if (!CollectionUtils.isEmpty(customizers)) { customizers = new ArrayList<>(customizers); AnnotationAwareOrderComparator.sort(customizers); - builder = builder.setCustomizers(customizers); + builder = builder.customizers(customizers); } return builder; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java index d60b88ca65..6d647e104e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/client/WebServiceTemplateAutoConfigurationTests.java @@ -16,82 +16,94 @@ package org.springframework.boot.autoconfigure.webservices.client; -import org.junit.After; +import java.util.function.Consumer; + import org.junit.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.webservices.client.WebServiceTemplateBuilder; import org.springframework.boot.webservices.client.WebServiceTemplateCustomizer; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link WebServiceTemplateAutoConfiguration - * WebServiceTemplateAutoConfiguration}. + * Tests for {@link WebServiceTemplateAutoConfiguration}. * + * @author Stephane Nicoll * @author Dmytro Nosan */ public class WebServiceTemplateAutoConfigurationTests { - private AnnotationConfigApplicationContext context; + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(WebServiceTemplateAutoConfiguration.class)); - @After - public void close() { - if (this.context != null) { - this.context.close(); - } + @Test + public void autoConfiguredBuilderShouldNotHaveMarshallerAndUnmarshaller() { + this.contextRunner.run(assertWebServiceTemplateBuilder((builder) -> { + WebServiceTemplate webServiceTemplate = builder.build(); + assertThat(webServiceTemplate.getUnmarshaller()).isNull(); + assertThat(webServiceTemplate.getMarshaller()).isNull(); + })); } @Test - public void webServiceTemplateShouldNotHaveMarshallerAndUnmarshaller() { - load(WebServiceTemplateConfig.class); - WebServiceTemplate webServiceTemplate = this.context - .getBean(WebServiceTemplate.class); - assertThat(webServiceTemplate.getUnmarshaller()).isNull(); - assertThat(webServiceTemplate.getMarshaller()).isNull(); + public void autoConfiguredBuilderShouldHaveHttpMessageSenderByDefault() { + this.contextRunner.run(assertWebServiceTemplateBuilder((builder) -> { + WebServiceTemplate webServiceTemplate = builder.build(); + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + WebServiceMessageSender messageSender = webServiceTemplate + .getMessageSenders()[0]; + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + })); } @Test - public void webServiceTemplateShouldUserCustomBuilder() { - load(CustomWebServiceTemplateBuilderConfig.class, WebServiceTemplateConfig.class); - WebServiceTemplate webServiceTemplate = this.context - .getBean(WebServiceTemplate.class); - assertThat(webServiceTemplate.getMarshaller()).isNotNull(); + public void webServiceTemplateWhenHasCustomBuilderShouldUseCustomBuilder() { + this.contextRunner + .withUserConfiguration(CustomWebServiceTemplateBuilderConfig.class) + .run(assertWebServiceTemplateBuilder((builder) -> { + WebServiceTemplate webServiceTemplate = builder.build(); + assertThat(webServiceTemplate.getMarshaller()) + .isSameAs(CustomWebServiceTemplateBuilderConfig.marshaller); + })); } @Test public void webServiceTemplateShouldApplyCustomizer() { - load(WebServiceTemplateCustomizerConfig.class, WebServiceTemplateConfig.class); - WebServiceTemplate webServiceTemplate = this.context - .getBean(WebServiceTemplate.class); - assertThat(webServiceTemplate.getUnmarshaller()).isNotNull(); + this.contextRunner.withUserConfiguration(WebServiceTemplateCustomizerConfig.class) + .run(assertWebServiceTemplateBuilder((builder) -> { + WebServiceTemplate webServiceTemplate = builder.build(); + assertThat(webServiceTemplate.getUnmarshaller()) + .isSameAs(WebServiceTemplateCustomizerConfig.unmarshaller); + })); } @Test public void builderShouldBeFreshForEachUse() { - load(DirtyWebServiceTemplateConfig.class); + this.contextRunner.withUserConfiguration(DirtyWebServiceTemplateConfig.class) + .run((context) -> { + assertThat(context).hasNotFailed(); + }); } - private void load(Class... config) { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(config); - ctx.register(WebServiceTemplateAutoConfiguration.class); - ctx.refresh(); - this.context = ctx; - } - - @Configuration - static class WebServiceTemplateConfig { - - @Bean - public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) { - return builder.build(); - } - + private ContextConsumer assertWebServiceTemplateBuilder( + Consumer builder) { + return (context) -> { + assertThat(context).hasSingleBean(WebServiceTemplateBuilder.class); + builder.accept(context.getBean(WebServiceTemplateBuilder.class)); + }; } @Configuration @@ -120,7 +132,7 @@ public class WebServiceTemplateAutoConfigurationTests { } private void breakBuilderOnNextCall(WebServiceTemplateBuilder builder) { - builder.addCustomizers((webServiceTemplate) -> { + builder.additionalCustomizers((webServiceTemplate) -> { throw new IllegalStateException(); }); } @@ -130,9 +142,11 @@ public class WebServiceTemplateAutoConfigurationTests { @Configuration static class CustomWebServiceTemplateBuilderConfig { + private static final Marshaller marshaller = new Jaxb2Marshaller(); + @Bean public WebServiceTemplateBuilder webServiceTemplateBuilder() { - return new WebServiceTemplateBuilder().setMarshaller(new Jaxb2Marshaller()); + return new WebServiceTemplateBuilder().setMarshaller(marshaller); } } @@ -140,9 +154,11 @@ public class WebServiceTemplateAutoConfigurationTests { @Configuration static class WebServiceTemplateCustomizerConfig { + private static final Unmarshaller unmarshaller = new Jaxb2Marshaller(); + @Bean public WebServiceTemplateCustomizer webServiceTemplateCustomizer() { - return (ws) -> ws.setUnmarshaller(new Jaxb2Marshaller()); + return (ws) -> ws.setUnmarshaller(unmarshaller); } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index beb46654bf..ed40a6892e 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -5634,6 +5634,7 @@ The following code shows a typical example: ---- + [[boot-features-webclient-customization]] === WebClient Customization There are three main approaches to `WebClient` customization, depending on how broadly you @@ -5652,35 +5653,6 @@ the point of injection. Finally, you can fall back to the original API and use `WebClient.create()`. In that case, no auto-configuration or `WebClientCustomizer` is applied. -[[boot-features-webservicetemplate]] -== Calling Web Services with `WebServiceTemplate` -If you need to call remote WEB services from your application, you can use the Spring -Framework's {spring-webservices-reference}#client-web-service-template[`WebServiceTemplate`] class. Since -`WebServiceTemplate` instances often need to be customized before being used, Spring Boot does -not provide any single auto-configured `WebServiceTemplate` bean. It does, however, -auto-configure a `WebServiceTemplateBuilder`, which can be used to create `WebServiceTemplate` -instances when needed. - -The following code shows a typical example: - -[source,java,indent=0] ----- - @Service - public class MyService { - - private final WebServiceTemplate webServiceTemplate; - - public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) { - this.webServiceTemplate = webServiceTemplateBuilder.build(); - } - - public DetailsResp someCall(DetailsReq detailsReq) { - return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION)); - - } - - } ----- [[boot-features-validation]] @@ -7416,6 +7388,51 @@ following example: +[[boot-features-webservices-template]] +== Calling Web Services with `WebServiceTemplate` +If you need to call remote Web services from your application, you can use the +{spring-webservices-reference}#client-web-service-template[`WebServiceTemplate`] class. +Since `WebServiceTemplate` instances often need to be customized before being used, Spring +Boot does not provide any single auto-configured `WebServiceTemplate` bean. It does, +however, auto-configure a `WebServiceTemplateBuilder`, which can be used to create +`WebServiceTemplate` instances when needed. + +The following code shows a typical example: + +[source,java,indent=0] +---- + @Service + public class MyService { + + private final WebServiceTemplate webServiceTemplate; + + public MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) { + this.webServiceTemplate = webServiceTemplateBuilder.build(); + } + + public DetailsResp someWsCall(DetailsReq detailsReq) { + return (DetailsResp) this.webServiceTemplate.marshalSendAndReceive(detailsReq, new SoapActionCallback(ACTION)); + + } + + } +---- + +By default, `WebServiceTemplateBuilder` detects a suitable HTTP-based +`WebServiceMessageSender` using the available HTTP client libraries on the classpath. You +can also customize read and connection timeouts as follows: + +[source,java,indent=0] +---- + @Bean + public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) { + return builder.messageSenders(new HttpWebServiceMessageSenderBuilder() + .setReadTimeout(5000).setConnectionTimeout(2000).build()).build(); + } +---- + + + [[boot-features-developing-auto-configuration]] == Creating Your Own Auto-configuration If you work in a company that develops shared libraries, or if you work on an open-source diff --git a/spring-boot-project/spring-boot/pom.xml b/spring-boot-project/spring-boot/pom.xml index dcbecba691..b268584e08 100644 --- a/spring-boot-project/spring-boot/pom.xml +++ b/spring-boot-project/spring-boot/pom.xml @@ -245,11 +245,6 @@ spring-orm true - - org.springframework.ws - spring-ws-core - true - org.springframework spring-oxm @@ -280,6 +275,11 @@ spring-security-web true + + org.springframework.ws + spring-ws-core + true + org.yaml snakeyaml diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java new file mode 100644 index 0000000000..e5c998b246 --- /dev/null +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilder.java @@ -0,0 +1,124 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import java.lang.reflect.Method; +import java.util.function.Supplier; + +import org.springframework.boot.web.client.ClientHttpRequestFactorySupplier; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +/** + * {@link WebServiceMessageSender} builder that can detect a suitable HTTP library based + * on the classpath. + * + * @author Stephane Nicoll + * @since 2.1.0 + */ +public class HttpWebServiceMessageSenderBuilder { + + private Integer connectionTimeout; + + private Integer readTimeout; + + private Supplier requestFactorySupplier; + + /** + * Set the connection timeout in milliseconds. + * @param connectionTimeout the connection timeout in milliseconds + * @return a new builder instance + */ + public HttpWebServiceMessageSenderBuilder setConnectionTimeout( + int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + return this; + } + + /** + * Set the read timeout in milliseconds. + * @param readTimeout the read timeout in milliseconds + * @return a new builder instance + */ + public HttpWebServiceMessageSenderBuilder setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; + return this; + } + + /** + * Set the {@code Supplier} of {@link ClientHttpRequestFactory} that should be called + * to create the HTTP-based {@link WebServiceMessageSender}. + * @param requestFactorySupplier the supplier for the request factory + * @return a new builder instance + */ + public HttpWebServiceMessageSenderBuilder requestFactory( + Supplier requestFactorySupplier) { + Assert.notNull(requestFactorySupplier, + "RequestFactory Supplier must not be null"); + this.requestFactorySupplier = requestFactorySupplier; + return this; + } + + public WebServiceMessageSender build() { + ClientHttpRequestFactory requestFactory = (this.requestFactorySupplier != null + ? this.requestFactorySupplier.get() + : new ClientHttpRequestFactorySupplier().get()); + if (this.connectionTimeout != null) { + new TimeoutRequestFactoryCustomizer(this.connectionTimeout, + "setConnectTimeout").customize(requestFactory); + } + if (this.readTimeout != null) { + new TimeoutRequestFactoryCustomizer(this.readTimeout, "setReadTimeout") + .customize(requestFactory); + } + return new ClientHttpRequestMessageSender(requestFactory); + } + + /** + * {@link ClientHttpRequestFactory} customizer to call a "set timeout" method. + */ + private static class TimeoutRequestFactoryCustomizer { + + private final int timeout; + + private final String methodName; + + TimeoutRequestFactoryCustomizer(int timeout, String methodName) { + this.timeout = timeout; + this.methodName = methodName; + } + + public void customize(ClientHttpRequestFactory factory) { + ReflectionUtils.invokeMethod(findMethod(factory), factory, this.timeout); + } + + private Method findMethod(ClientHttpRequestFactory factory) { + Method method = ReflectionUtils.findMethod(factory.getClass(), + this.methodName, int.class); + if (method != null) { + return method; + } + throw new IllegalStateException("Request factory " + factory.getClass() + + " does not have a " + this.methodName + "(int) method"); + } + + } + +} diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java index 4a185900d5..c8d831c3fb 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java @@ -16,69 +16,46 @@ package org.springframework.boot.webservices.client; -import java.lang.reflect.Field; import java.net.URI; -import java.time.Duration; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Optional; import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; import javax.xml.transform.TransformerFactory; import org.springframework.beans.BeanUtils; -import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; -import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; -import org.springframework.util.ReflectionUtils; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.FaultMessageResolver; import org.springframework.ws.client.core.WebServiceTemplate; import org.springframework.ws.client.support.destination.DestinationProvider; import org.springframework.ws.client.support.interceptor.ClientInterceptor; import org.springframework.ws.transport.WebServiceMessageSender; -import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; -import org.springframework.ws.transport.http.HttpComponentsMessageSender; -import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; /** - * Builder that can be used to configure and create a - * {@link org.springframework.ws.client.core.WebServiceTemplate}. By default the built - * {@link org.springframework.ws.client.core.WebServiceTemplate} will attempt to use the - * most suitable {@link org.springframework.ws.transport.WebServiceMessageSender}, call - * {@link #detectWebServiceMessageSender(boolean) detectWebServiceMessageSender(false)} if - * you prefer to keep the default. In a typical auto-configured Spring Boot application - * this builder is available as a bean and can be injected whenever a - * {@link WebServiceTemplate} is needed. + * Builder that can be used to configure and create a {@link WebServiceTemplate}. Provides + * convenience methods to register {@link #messageSenders(WebServiceMessageSender...) + * message senders}, {@link #interceptors(ClientInterceptor...) client interceptors} and + * {@link #customizers(WebServiceTemplateCustomizer...) customizers}. + *

+ * By default the built {@link WebServiceTemplate} uses the most suitable HTTP-based + * {@link WebServiceMessageSender}, call {@link #detectHttpMessageSender(boolean) + * detectHttpMessageSender(false)} if you prefer to keep the default. In a typical + * auto-configured Spring Boot application this builder is available as a bean and can be + * injected whenever a {@link WebServiceTemplate} is needed. * * @author Dmytro Nosan + * @author Stephane Nicoll + * @since 2.1.0 */ public class WebServiceTemplateBuilder { - private static final Map> MESSAGE_SENDER_FACTORY_CLASSES; - - static { - Map> candidates = new LinkedHashMap<>(); - candidates.put("org.apache.http.client.HttpClient", - HttpComponentsMessageSenderFactory.class); - candidates.put("org.springframework.http.client.ClientHttpRequestFactory", - ClientHttpRequestMessageSenderFactory.class); - MESSAGE_SENDER_FACTORY_CLASSES = Collections.unmodifiableMap(candidates); - } + private final boolean detectHttpMessageSender; private final Set interceptors; @@ -86,9 +63,7 @@ public class WebServiceTemplateBuilder { private final Set customizers; - private final Set> webServiceMessageSenderSuppliers; - - private final Set webServiceMessageSenderCustomizers; + private final WebServiceMessageSenders messageSenders; private final Marshaller marshaller; @@ -100,141 +75,210 @@ public class WebServiceTemplateBuilder { private final WebServiceMessageFactory messageFactory; - private final boolean detectWebServiceMessageSender; - public WebServiceTemplateBuilder(WebServiceTemplateCustomizer... customizers) { - this(Collections.emptySet(), Collections.emptySet(), + this(true, Collections.emptySet(), Collections.emptySet(), append(Collections.emptySet(), customizers), - Collections.emptySet(), Collections.emptySet(), null, null, null, null, - null, true); + new WebServiceMessageSenders(), null, null, null, null, null); } - private WebServiceTemplateBuilder(Set interceptors, + private WebServiceTemplateBuilder(boolean detectHttpMessageSender, + Set interceptors, Set internalCustomizers, Set customizers, - Set> webServiceMessageSenderSuppliers, - Set webServiceMessageSenderCustomizers, - Marshaller marshaller, Unmarshaller unmarshaller, - DestinationProvider destinationProvider, + WebServiceMessageSenders messageSenders, Marshaller marshaller, + Unmarshaller unmarshaller, DestinationProvider destinationProvider, Class transformerFactoryClass, - WebServiceMessageFactory messageFactory, - boolean detectWebServiceMessageSender) { + WebServiceMessageFactory messageFactory) { this.interceptors = interceptors; this.internalCustomizers = internalCustomizers; this.customizers = customizers; - this.webServiceMessageSenderSuppliers = webServiceMessageSenderSuppliers; - this.webServiceMessageSenderCustomizers = webServiceMessageSenderCustomizers; + this.messageSenders = messageSenders; + this.detectHttpMessageSender = detectHttpMessageSender; this.marshaller = marshaller; this.unmarshaller = unmarshaller; this.destinationProvider = destinationProvider; this.transformerFactoryClass = transformerFactoryClass; this.messageFactory = messageFactory; - this.detectWebServiceMessageSender = detectWebServiceMessageSender; } /** - * Set {@link ClientInterceptor ClientInterceptors} that should be used with the - * {@link WebServiceTemplate}. Interceptors are applied in the order that they were - * added after builder configuration has been applied. - * - * Note! Override existing interceptors - * @param interceptors the interceptors to set + * Set if a suitable HTTP-based {@link WebServiceMessageSender} should be detected + * based on the classpath. Default is {@code true}. + * @param detectHttpMessageSender if a HTTP-based {@link WebServiceMessageSender} + * should be detected * @return a new builder instance - * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + * @see HttpWebServiceMessageSenderBuilder */ - public WebServiceTemplateBuilder setInterceptors(ClientInterceptor... interceptors) { - Assert.notNull(interceptors, "interceptors must not be null"); - return setInterceptors(Arrays.asList(interceptors)); + public WebServiceTemplateBuilder detectHttpMessageSender( + boolean detectHttpMessageSender) { + return new WebServiceTemplateBuilder(detectHttpMessageSender, this.interceptors, + this.internalCustomizers, this.customizers, this.messageSenders, + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory); } /** - * Set {@link ClientInterceptor ClientInterceptors} that should be used with the - * {@link WebServiceTemplate}. Interceptors are applied in the order that they were - * added after builder configuration has been applied. - * - * Note! Override existing interceptors + * Sets the {@link WebServiceMessageSender WebServiceMessageSenders} that should be + * used with the {@link WebServiceTemplate}. Setting this value will replace any + * previously defined message senders, including the HTTP-based message sender, if + * any. Consider using {@link #additionalMessageSenders(WebServiceMessageSender...)} + * to keep it with user-defined message senders. + * @param messageSenders the message senders to set + * @return a new builder instance. + * @see #additionalMessageSenders(WebServiceMessageSender...) + * @see #detectHttpMessageSender(boolean) + */ + public WebServiceTemplateBuilder messageSenders( + WebServiceMessageSender... messageSenders) { + Assert.notNull(messageSenders, "MessageSenders must not be null"); + return messageSenders(Arrays.asList(messageSenders)); + } + + /** + * Sets the {@link WebServiceMessageSender WebServiceMessageSenders} that should be + * used with the {@link WebServiceTemplate}. Setting this value will replace any + * previously defined message senders, including the HTTP-based message sender, if + * any. Consider using {@link #additionalMessageSenders(Collection)} to keep it with + * user-defined message senders. + * @param messageSenders the message senders to set + * @return a new builder instance. + * @see #additionalMessageSenders(Collection) + * @see #detectHttpMessageSender(boolean) + */ + public WebServiceTemplateBuilder messageSenders( + Collection messageSenders) { + Assert.notNull(messageSenders, "MessageSenders must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders.set(messageSenders), this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); + } + + /** + * Add additional {@link WebServiceMessageSender WebServiceMessageSenders} that should + * be used with the {@link WebServiceTemplate}. + * @param messageSenders the message senders to add + * @return a new builder instance. + * @see #messageSenders(WebServiceMessageSender...) + */ + public WebServiceTemplateBuilder additionalMessageSenders( + WebServiceMessageSender... messageSenders) { + Assert.notNull(messageSenders, "MessageSenders must not be null"); + return additionalMessageSenders(Arrays.asList(messageSenders)); + } + + /** + * Add additional {@link WebServiceMessageSender WebServiceMessageSenders} that should + * be used with the {@link WebServiceTemplate}. + * @param messageSenders the message senders to add + * @return a new builder instance. + * @see #messageSenders(Collection) + */ + public WebServiceTemplateBuilder additionalMessageSenders( + Collection messageSenders) { + Assert.notNull(messageSenders, "MessageSenders must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders.add(messageSenders), this.marshaller, + this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); + } + + /** + * Set the {@link ClientInterceptor ClientInterceptors} that should be used with the + * {@link WebServiceTemplate}. Setting this value will replace any previously defined + * interceptors. * @param interceptors the interceptors to set * @return a new builder instance - * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + * @see #additionalInterceptors(ClientInterceptor...) */ - public WebServiceTemplateBuilder setInterceptors( + public WebServiceTemplateBuilder interceptors(ClientInterceptor... interceptors) { + Assert.notNull(interceptors, "Interceptors must not be null"); + return interceptors(Arrays.asList(interceptors)); + } + + /** + * Set the {@link ClientInterceptor ClientInterceptors} that should be used with the + * {@link WebServiceTemplate}. Setting this value will replace any previously defined + * interceptors. + * @param interceptors the interceptors to set + * @return a new builder instance + * @see #additionalInterceptors(Collection) + */ + public WebServiceTemplateBuilder interceptors( Collection interceptors) { - Assert.notNull(interceptors, "interceptors must not be null"); - return new WebServiceTemplateBuilder( + Assert.notNull(interceptors, "Interceptors must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, append(Collections.emptySet(), interceptors), - this.internalCustomizers, this.customizers, - this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.internalCustomizers, this.customizers, this.messageSenders, + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory); } /** * Add additional {@link ClientInterceptor ClientInterceptors} that should be used - * with the {@link WebServiceTemplate}. Interceptors are applied in the order that - * they were added after builder configuration has been applied. + * with the {@link WebServiceTemplate}. * @param interceptors the interceptors to add * @return a new builder instance - * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + * @see #interceptors(ClientInterceptor...) */ - public WebServiceTemplateBuilder addInterceptors(ClientInterceptor... interceptors) { - Assert.notNull(interceptors, "interceptors must not be null"); - return addInterceptors(Arrays.asList(interceptors)); + public WebServiceTemplateBuilder additionalInterceptors( + ClientInterceptor... interceptors) { + Assert.notNull(interceptors, "Interceptors must not be null"); + return additionalInterceptors(Arrays.asList(interceptors)); } /** * Add additional {@link ClientInterceptor ClientInterceptors} that should be used - * with the {@link WebServiceTemplate}. Interceptors are applied in the order that - * they were added after builder configuration has been applied. + * with the {@link WebServiceTemplate}. * @param interceptors the interceptors to add * @return a new builder instance - * @see WebServiceTemplate#setInterceptors(ClientInterceptor[]) + * @see #interceptors(Collection) */ - public WebServiceTemplateBuilder addInterceptors( + public WebServiceTemplateBuilder additionalInterceptors( Collection interceptors) { - Assert.notNull(interceptors, "interceptors must not be null"); - return new WebServiceTemplateBuilder(append(this.interceptors, interceptors), - this.internalCustomizers, this.customizers, - this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + Assert.notNull(interceptors, "Interceptors must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + append(this.interceptors, interceptors), this.internalCustomizers, + this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order - * that they were added after builder configuration has been applied. - * - * Note! Override existing customizers + * that they were added after builder configuration has been applied. Setting this + * value will replace any previously configured customizers. * @param customizers the customizers to set * @return a new builder instance + * @see #additionalCustomizers(WebServiceTemplateCustomizer...) */ + public WebServiceTemplateBuilder customizers( + WebServiceTemplateCustomizer... customizers) { + Assert.notNull(customizers, "Customizers must not be null"); + return customizers(Arrays.asList(customizers)); + } - public WebServiceTemplateBuilder setCustomizers( + /** + * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should + * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order + * that they were added after builder configuration has been applied. Setting this + * value will replace any previously configured customizers. + * @param customizers the customizers to set + * @return a new builder instance + * @see #additionalCustomizers(Collection) + */ + public WebServiceTemplateBuilder customizers( Collection customizers) { - Assert.notNull(customizers, "customizers must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, + Assert.notNull(customizers, "Customizers must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, append(Collections.emptySet(), customizers), - this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); - } - - /** - * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should - * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order - * that they were added after builder configuration has been applied. - * - * Note! Override existing customizers - * @param customizers the customizers to set - * @return a new builder instance - */ - public WebServiceTemplateBuilder setCustomizers( - WebServiceTemplateCustomizer... customizers) { - Assert.notNull(customizers, "customizers must not be null"); - return setCustomizers(Arrays.asList(customizers)); + this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** @@ -243,11 +287,12 @@ public class WebServiceTemplateBuilder { * in the order that they were added after builder configuration has been applied. * @param customizers the customizers to add * @return a new builder instance + * @see #customizers(WebServiceTemplateCustomizer...) */ - public WebServiceTemplateBuilder addCustomizers( + public WebServiceTemplateBuilder additionalCustomizers( WebServiceTemplateCustomizer... customizers) { - Assert.notNull(customizers, "customizers must not be null"); - return addCustomizers(Arrays.asList(customizers)); + Assert.notNull(customizers, "Customizers must not be null"); + return additionalCustomizers(Arrays.asList(customizers)); } /** @@ -256,342 +301,160 @@ public class WebServiceTemplateBuilder { * in the order that they were added after builder configuration has been applied. * @param customizers the customizers to add * @return a new builder instance + * @see #customizers(Collection) */ - - public WebServiceTemplateBuilder addCustomizers( + public WebServiceTemplateBuilder additionalCustomizers( Collection customizers) { - Assert.notNull(customizers, "customizers must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - append(this.customizers, customizers), - this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + Assert.notNull(customizers, "Customizers must not be null"); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, + append(this.customizers, customizers), this.messageSenders, + this.marshaller, this.unmarshaller, this.destinationProvider, + this.transformerFactoryClass, this.messageFactory); } /** - * Sets the {@code Suppliers} of {@link WebServiceMessageSender} that should be called - * each time when {@link #configure(WebServiceTemplate)} method is called. - * - * Note! Override existing WebServiceMessageSender {@code suppliers} - * @param webServiceMessageSenderSuppliers Suppliers for the messageSenders + * Indicates whether the connection should be checked for fault indicators + * ({@code true}), or whether we should rely on the message only ({@code false}). + * @param checkConnectionForFault whether to check for fault indicators * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) + * @see WebServiceTemplate#setCheckConnectionForFault(boolean) */ - - public WebServiceTemplateBuilder setWebServiceMessageSenders( - Collection> webServiceMessageSenderSuppliers) { - Assert.notNull(webServiceMessageSenderSuppliers, - "webServiceMessageSenderSuppliers must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, - append(Collections - .>emptySet(), - webServiceMessageSenderSuppliers), - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); - } - - /** - * Add additional {@code Suppliers} of {@link WebServiceMessageSender} that should be - * called each time when {@link #configure(WebServiceTemplate)} method is called. - * @param webServiceMessageSenderSuppliers Suppliers for the messageSenders - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - */ - public WebServiceTemplateBuilder addWebServiceMessageSenders( - Collection> webServiceMessageSenderSuppliers) { - Assert.notNull(webServiceMessageSenderSuppliers, - "webServiceMessageSenderSuppliers must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, - append(this.webServiceMessageSenderSuppliers, - webServiceMessageSenderSuppliers), - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); - } - - /** - * Set {@link WebServiceTemplate#setCheckConnectionForFault(boolean) - * setCheckConnectionForFault} on the underlying. - * @param checkConnectionForFault Specify whether checkConnectionForFault should be - * enabled or not. - * @return a new builder instance. - **/ public WebServiceTemplateBuilder setCheckConnectionForFault( boolean checkConnectionForFault) { - return new WebServiceTemplateBuilder(this.interceptors, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, append(this.internalCustomizers, new CheckConnectionFaultCustomizer(checkConnectionForFault)), - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** - * Set {@link WebServiceTemplate#setCheckConnectionForError(boolean) - * setCheckConnectionForError} on the underlying. - * @param checkConnectionForError Specify whether checkConnectionForError should be - * enabled or not. + * Indicates whether the connection should be checked for error indicators + * ({@code true}), or whether these should be ignored ({@code false}). + * @param checkConnectionForError whether to check for error indicators * @return a new builder instance. - **/ - + * @see WebServiceTemplate#setCheckConnectionForError(boolean) + */ public WebServiceTemplateBuilder setCheckConnectionForError( boolean checkConnectionForError) { - return new WebServiceTemplateBuilder(this.interceptors, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, append(this.internalCustomizers, new CheckConnectionForErrorCustomizer(checkConnectionForError)), - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** - * Sets the {@code Supplier} of {@link WebServiceMessageSender} that should be called - * each time when {@link #configure(WebServiceTemplate)} method is called. - * - * Note! Override existing WebServiceMessageSender {@code suppliers} - * @param webServiceMessageSenderSupplier Supplier for the messageSender - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - * @see #setWebServiceMessageSenders(Collection) - */ - - public WebServiceTemplateBuilder setWebServiceMessageSender( - Supplier webServiceMessageSenderSupplier) { - Assert.notNull(webServiceMessageSenderSupplier, - "webServiceMessageSenderSupplier must not be null"); - return setWebServiceMessageSenders( - Collections.singleton(webServiceMessageSenderSupplier)); - } - - /** - * Add additional {@code Supplier} of {@link WebServiceMessageSender} that should be - * called each time when {@link #configure(WebServiceTemplate)} method is called. - * @param webServiceMessageSenderSupplier Supplier for the messageSender - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - * @see #addWebServiceMessageSenders(Collection) - */ - public WebServiceTemplateBuilder addWebServiceMessageSender( - Supplier webServiceMessageSenderSupplier) { - Assert.notNull(webServiceMessageSenderSupplier, - "webServiceMessageSenderSupplier must not be null"); - return addWebServiceMessageSenders( - Collections.singleton(webServiceMessageSenderSupplier)); - } - - /** - * Sets the {@code Class} of {@link WebServiceMessageSender} that should be created - * each time when {@link #configure(WebServiceTemplate)} method is called. - * - * Note! Override existing WebServiceMessageSender {@code suppliers} - * @param webServiceMessageSenderClass {@code Class} of - * {@link WebServiceMessageSender} - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - * @see #setWebServiceMessageSender(Supplier) - * @see BeanUtils#instantiateClass(Class) - */ - - public WebServiceTemplateBuilder setWebServiceMessageSender( - Class webServiceMessageSenderClass) { - Assert.notNull(webServiceMessageSenderClass, - "webServiceMessageSenderClass must not be null"); - return setWebServiceMessageSender( - supplier(webServiceMessageSenderClass, BeanUtils::instantiateClass)); - } - - /** - * Add additional {@code Class} of {@link WebServiceMessageSender} that should be - * created each time when {@link #configure(WebServiceTemplate)} method is called. - * @param webServiceMessageSenderClass {@code Class} of - * {@link WebServiceMessageSender} - * @return a new builder instance. - * @see WebServiceTemplate#setMessageSenders(WebServiceMessageSender[]) - * @see #addWebServiceMessageSender(Supplier) - * @see BeanUtils#instantiateClass(Class) - */ - public WebServiceTemplateBuilder addWebServiceMessageSender( - Class webServiceMessageSenderClass) { - Assert.notNull(webServiceMessageSenderClass, - "webServiceMessageSenderClass must not be null"); - return addWebServiceMessageSender( - supplier(webServiceMessageSenderClass, BeanUtils::instantiateClass)); - } - - /** - * Sets the message factory used for creating messages. - * @param messageFactory instance of WebServiceMessageFactory + * Sets the {@link WebServiceMessageFactory} to use for creating messages. + * @param messageFactory the message factory to use for creating messages * @return a new builder instance. * @see WebServiceTemplate#setMessageFactory(WebServiceMessageFactory) **/ - public WebServiceTemplateBuilder setWebServiceMessageFactory( WebServiceMessageFactory messageFactory) { Assert.notNull(messageFactory, "messageFactory must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - messageFactory, this.detectWebServiceMessageSender); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, messageFactory); } /** - * Set {@link WebServiceTemplate#setUnmarshaller(Unmarshaller) unmarshaller} on the - * underlying. - * @param unmarshaller message unmarshaller + * Set the {@link Unmarshaller} to use to deserialize messages. + * @param unmarshaller the message unmarshaller * @return a new builder instance. * @see WebServiceTemplate#setUnmarshaller(Unmarshaller) **/ public WebServiceTemplateBuilder setUnmarshaller(Unmarshaller unmarshaller) { - Assert.notNull(unmarshaller, "unmarshaller must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, unmarshaller, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, this.marshaller, unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.messageFactory); } /** - * Set {@link WebServiceTemplate#setMarshaller(Marshaller) marshaller} on the - * underlying. - * @param marshaller message marshaller + * Set the {@link Marshaller} to use to serialize messages. + * @param marshaller the message marshaller * @return a new builder instance. * @see WebServiceTemplate#setMarshaller(Marshaller) **/ public WebServiceTemplateBuilder setMarshaller(Marshaller marshaller) { - Assert.notNull(marshaller, "marshaller must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, marshaller, this.unmarshaller, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, marshaller, this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.messageFactory); } /** - * Sets the connection timeout in milliseconds on the underlying. - * @param connectionTimeout the connection timeout in milliseconds + * Set the {@link FaultMessageResolver} to use. + * @param faultMessageResolver the fault message resolver to use * @return a new builder instance. - * @throws java.lang.IllegalStateException if the underlying source doesn't support a - * connection timeout. + * @see WebServiceTemplate#setFaultMessageResolver(FaultMessageResolver) */ - public WebServiceTemplateBuilder setConnectionTimeout(int connectionTimeout) { - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - append(this.webServiceMessageSenderCustomizers, - new ConnectionTimeoutWebServiceMessageSenderCustomizer( - connectionTimeout)), - this.marshaller, this.unmarshaller, this.destinationProvider, - this.transformerFactoryClass, this.messageFactory, - this.detectWebServiceMessageSender); - } - - /** - * Sets the read timeout in milliseconds on the underlying. - * @param readTimeout the read timeout in milliseconds - * @return a new builder instance. - * @throws java.lang.IllegalStateException if the underlying source doesn't support a - * read timeout. - */ - public WebServiceTemplateBuilder setReadTimeout(int readTimeout) { - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - append(this.webServiceMessageSenderCustomizers, - new ReadTimeoutWebServiceMessageSenderCustomizer(readTimeout)), - this.marshaller, this.unmarshaller, this.destinationProvider, - this.transformerFactoryClass, this.messageFactory, - this.detectWebServiceMessageSender); - } - - /** - * Set {@link WebServiceTemplate#setFaultMessageResolver(FaultMessageResolver) - * faultMessageResolver} on the underlying. - * @param faultMessageResolver faultMessageResolver may be set to null to disable - * fault handling. - * @return a new builder instance. - **/ public WebServiceTemplateBuilder setFaultMessageResolver( FaultMessageResolver faultMessageResolver) { - return new WebServiceTemplateBuilder(this.interceptors, + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, append(this.internalCustomizers, new FaultMessageResolverCustomizer(faultMessageResolver)), - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + this.customizers, this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, this.transformerFactoryClass, + this.messageFactory); } /** - * Set {@link WebServiceTemplate#setTransformerFactoryClass(Class) - * setTransformerFactoryClass} on the underlying. - * @param transformerFactoryClass boolean value + * Set the {@link TransformerFactory} implementation to use. + * @param transformerFactoryClass the transformer factory implementation to use * @return a new builder instance. - **/ - + * @see WebServiceTemplate#setTransformerFactoryClass(Class) + */ public WebServiceTemplateBuilder setTransformerFactoryClass( Class transformerFactoryClass) { - Assert.notNull(transformerFactoryClass, - "transformerFactoryClass must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, this.marshaller, this.unmarshaller, + this.destinationProvider, transformerFactoryClass, this.messageFactory); } /** * Set the default URI to be used on operations that do not have a URI parameter. - * - * Note!Typically, either this property is set, or + *

+ * Typically, either this property is set, or * {@link #setDestinationProvider(DestinationProvider)}, but not both. * @param defaultUri the destination provider URI to be used on operations that do not * have a URI parameter. * @return a new builder instance. + * @see #setDestinationProvider(DestinationProvider) */ public WebServiceTemplateBuilder setDefaultUri(String defaultUri) { - Assert.hasText(defaultUri, "defaultUri must not be empty"); + Assert.hasText(defaultUri, "DefaultUri must not be empty"); return setDestinationProvider(() -> URI.create(defaultUri)); } /** - * Set {@link WebServiceTemplate#setDestinationProvider(DestinationProvider) - * destinationProvider} on the underlying. - * - * Note!Typically, either this property is set, or - * {@link #setDefaultUri(String)}, but not both. - * @param destinationProvider the destination provider URI to be used on operations - * that do not have a URI parameter. + * Set the {@link DestinationProvider} to use + *

+ * Typically, either this property is set, or {@link #setDefaultUri(String)}, but not + * both. + * @param destinationProvider the destination provider to be used on operations that + * do not have a URI parameter. * @return a new builder instance. + * @see WebServiceTemplate#setDestinationProvider(DestinationProvider) */ public WebServiceTemplateBuilder setDestinationProvider( DestinationProvider destinationProvider) { Assert.notNull(destinationProvider, "destinationProvider must not be null"); - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, destinationProvider, this.transformerFactoryClass, - this.messageFactory, this.detectWebServiceMessageSender); - } - - /** - * Set if the {@link WebServiceMessageSender} should be detected based on the - * classpath. Default is {@code true}. - * @param detectWebServiceMessageSender if the {@link WebServiceMessageSender} should - * be detected - * @return a new builder instance - */ - public WebServiceTemplateBuilder detectWebServiceMessageSender( - boolean detectWebServiceMessageSender) { - return new WebServiceTemplateBuilder(this.interceptors, this.internalCustomizers, - this.customizers, this.webServiceMessageSenderSuppliers, - this.webServiceMessageSenderCustomizers, this.marshaller, - this.unmarshaller, this.destinationProvider, this.transformerFactoryClass, - this.messageFactory, detectWebServiceMessageSender); + return new WebServiceTemplateBuilder(this.detectHttpMessageSender, + this.interceptors, this.internalCustomizers, this.customizers, + this.messageSenders, this.marshaller, this.unmarshaller, + destinationProvider, this.transformerFactoryClass, this.messageFactory); } /** @@ -614,10 +477,9 @@ public class WebServiceTemplateBuilder { * @see WebServiceTemplateBuilder#build() * @see #configure(WebServiceTemplate) */ - public T build(Class webServiceTemplateClass) { Assert.notNull(webServiceTemplateClass, - "webServiceTemplateClass must not be null"); + "WebServiceTemplateClass must not be null"); return configure(BeanUtils.instantiateClass(webServiceTemplateClass)); } @@ -631,97 +493,53 @@ public class WebServiceTemplateBuilder { */ public T configure(T webServiceTemplate) { Assert.notNull(webServiceTemplate, "webServiceTemplate must not be null"); - - configureSenders(webServiceTemplate); - + configureMessageSenders(webServiceTemplate); if (!CollectionUtils.isEmpty(this.internalCustomizers)) { for (WebServiceTemplateCustomizer internalCustomizer : this.internalCustomizers) { internalCustomizer.customize(webServiceTemplate); } } - if (this.marshaller != null) { webServiceTemplate.setMarshaller(this.marshaller); } - if (this.unmarshaller != null) { webServiceTemplate.setUnmarshaller(this.unmarshaller); } - if (this.destinationProvider != null) { webServiceTemplate.setDestinationProvider(this.destinationProvider); } - if (this.transformerFactoryClass != null) { webServiceTemplate.setTransformerFactoryClass(this.transformerFactoryClass); } - if (this.messageFactory != null) { webServiceTemplate.setMessageFactory(this.messageFactory); } - - if (!CollectionUtils.isEmpty(this.customizers)) { - for (WebServiceTemplateCustomizer customizer : this.customizers) { - customizer.customize(webServiceTemplate); - } - } - if (!CollectionUtils.isEmpty(this.interceptors)) { webServiceTemplate.setInterceptors( append(this.interceptors, webServiceTemplate.getInterceptors()) .toArray(new ClientInterceptor[0])); } - + if (!CollectionUtils.isEmpty(this.customizers)) { + for (WebServiceTemplateCustomizer customizer : this.customizers) { + customizer.customize(webServiceTemplate); + } + } return webServiceTemplate; } - private void configureSenders(T webServiceTemplate) { - - if (!CollectionUtils.isEmpty(this.webServiceMessageSenderSuppliers)) { - Set webServiceMessageSenders = new LinkedHashSet<>(); - for (Supplier webServiceMessageSenderSupplier : this.webServiceMessageSenderSuppliers) { - webServiceMessageSenders.add(webServiceMessageSenderSupplier.get()); - } + private void configureMessageSenders( + T webServiceTemplate) { + if (this.messageSenders.isOnlyAdditional() && this.detectHttpMessageSender) { + Set mergedMessageSenders = append( + this.messageSenders.getMessageSenders(), + new HttpWebServiceMessageSenderBuilder().build()); webServiceTemplate.setMessageSenders( - webServiceMessageSenders.toArray(new WebServiceMessageSender[0])); + mergedMessageSenders.toArray(new WebServiceMessageSender[0])); } - else if (this.detectWebServiceMessageSender) { - webServiceTemplate.setMessageSenders( - new WebServiceMessageSender[] { detectMessageSender() }); + else if (!CollectionUtils.isEmpty(this.messageSenders.getMessageSenders())) { + webServiceTemplate.setMessageSenders(this.messageSenders.getMessageSenders() + .toArray(new WebServiceMessageSender[0])); } - - if (!CollectionUtils.isEmpty(this.webServiceMessageSenderCustomizers)) { - if (!ObjectUtils.isEmpty(webServiceTemplate.getMessageSenders())) { - for (WebServiceMessageSender webServiceMessageSender : webServiceTemplate - .getMessageSenders()) { - for (WebServiceMessageSenderCustomizer webServiceMessageSenderCustomizer : this.webServiceMessageSenderCustomizers) { - webServiceMessageSenderCustomizer - .customize(webServiceMessageSender); - } - } - } - } - } - - private WebServiceMessageSender detectMessageSender() { - ClassLoader classLoader = getClass().getClassLoader(); - for (Map.Entry> candidate : MESSAGE_SENDER_FACTORY_CLASSES - .entrySet()) { - if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { - WebServiceMessageSenderFactory webServiceMessageSenderFactory = BeanUtils - .instantiateClass(candidate.getValue()); - Optional webServiceMessageSender = webServiceMessageSenderFactory - .create(); - if (webServiceMessageSender.isPresent()) { - return webServiceMessageSender.get(); - } - } - } - return new HttpUrlConnectionMessageSender(); - } - - private static Supplier supplier(T value, Function mapper) { - return () -> mapper.apply(value); } private static Set append(Set set, T[] additions) { @@ -741,55 +559,44 @@ public class WebServiceTemplateBuilder { return Collections.unmodifiableSet(result); } - private interface WebServiceMessageSenderFactory { + /** + * Collect user-defined {@link WebServiceMessageSender} and whether only additional + * message senders were added or not. + */ + private static class WebServiceMessageSenders { - Optional create(); + private final boolean onlyAdditional; - } + private Set messageSenders; - private interface WebServiceMessageSenderCustomizer { - - void customize(WebServiceMessageSender webServiceMessageSender); - - } - - private static final class ClientHttpRequestMessageSenderFactory - implements WebServiceMessageSenderFactory { - - private static final Map REQUEST_FACTORY_CANDIDATES; - - static { - Map candidates = new LinkedHashMap<>(); - candidates.put("okhttp3.OkHttpClient", - "org.springframework.http.client.OkHttp3ClientHttpRequestFactory"); - REQUEST_FACTORY_CANDIDATES = Collections.unmodifiableMap(candidates); + WebServiceMessageSenders() { + this(true, Collections.emptySet()); } - @Override - public Optional create() { - ClassLoader classLoader = getClass().getClassLoader(); - for (Map.Entry candidate : REQUEST_FACTORY_CANDIDATES - .entrySet()) { - if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { - Class factoryClass = ClassUtils - .resolveClassName(candidate.getValue(), classLoader); - ClientHttpRequestFactory clientHttpRequestFactory = (ClientHttpRequestFactory) BeanUtils - .instantiateClass(factoryClass); - return Optional.of( - new ClientHttpRequestMessageSender(clientHttpRequestFactory)); - } - } - return Optional.empty(); + private WebServiceMessageSenders(boolean onlyAdditional, + Set messageSenders) { + this.onlyAdditional = onlyAdditional; + this.messageSenders = messageSenders; } - } + public boolean isOnlyAdditional() { + return this.onlyAdditional; + } - private static final class HttpComponentsMessageSenderFactory - implements WebServiceMessageSenderFactory { + public Set getMessageSenders() { + return this.messageSenders; + } - @Override - public Optional create() { - return Optional.of(new HttpComponentsMessageSender()); + public WebServiceMessageSenders set( + Collection messageSenders) { + return new WebServiceMessageSenders(false, + new LinkedHashSet<>(messageSenders)); + } + + public WebServiceMessageSenders add( + Collection messageSenders) { + return new WebServiceMessageSenders(this.onlyAdditional, + append(this.messageSenders, messageSenders)); } } @@ -855,252 +662,4 @@ public class WebServiceTemplateBuilder { } - /** - * {@link WebServiceMessageSenderCustomizer} to set connection timeout. - */ - private static final class ConnectionTimeoutWebServiceMessageSenderCustomizer - extends TimeoutWebServiceMessageSenderCustomizer { - - private ConnectionTimeoutWebServiceMessageSenderCustomizer(int connectTimeout) { - super(connectTimeout, Timeout.CONNECTION); - } - - } - - /** - * {@link WebServiceMessageSenderCustomizer} to set read timeout. - */ - private static final class ReadTimeoutWebServiceMessageSenderCustomizer - extends TimeoutWebServiceMessageSenderCustomizer { - - private ReadTimeoutWebServiceMessageSenderCustomizer(int readTimeout) { - super(readTimeout, Timeout.READ); - } - - } - - private abstract static class TimeoutWebServiceMessageSenderCustomizer - implements WebServiceMessageSenderCustomizer { - - private static final Map>> CUSTOMIZERS; - - static { - Map>> candidates = new LinkedHashMap<>(); - candidates.put( - "org.springframework.ws.transport.http.HttpComponentsMessageSender", - HttpComponentsTimeoutCustomizer.class); - candidates.put( - "org.springframework.ws.transport.http.ClientHttpRequestMessageSender", - ClientHttpRequestTimeoutCustomizer.class); - candidates.put( - "org.springframework.ws.transport.http.HttpUrlConnectionMessageSender", - HttpUrlConnectionTimeoutCustomizer.class); - CUSTOMIZERS = Collections.unmodifiableMap(candidates); - } - - private final Timeout type; - - private final int timeout; - - TimeoutWebServiceMessageSenderCustomizer(int timeout, Timeout type) { - this.timeout = timeout; - this.type = type; - } - - @Override - public final void customize(WebServiceMessageSender webServiceMessageSender) { - ClassLoader classLoader = getClass().getClassLoader(); - customize(CUSTOMIZERS, webServiceMessageSender, this.type, this.timeout, - classLoader); - - } - - @SuppressWarnings("unchecked") - private static void customize( - Map>> customizers, - T target, Timeout type, int timeout, ClassLoader classLoader) { - for (Map.Entry>> candidate : customizers - .entrySet()) { - if (ClassUtils.isPresent(candidate.getKey(), classLoader)) { - Class candidateClass = ClassUtils - .resolveClassName(candidate.getKey(), classLoader); - if (ClassUtils.isAssignable(candidateClass, target.getClass())) { - TimeoutCustomizer timeoutCustomizer = BeanUtils - .instantiateClass(candidate.getValue()); - customize(timeoutCustomizer, target, type, timeout); - return; - } - } - } - throw new IllegalStateException("There is no way to customize '" - + target.getClass() + "' " + "with '" + type.name().toLowerCase() - + "Timeout'. Please use a custom " + "customizer."); - - } - - private static void customize(TimeoutCustomizer customizer, T target, - Timeout type, int timeout) { - if (type == Timeout.CONNECTION) { - customizer.setConnectionTimeout(target, timeout); - } - else if (type == Timeout.READ) { - customizer.setReadTimeout(target, timeout); - } - } - - interface TimeoutCustomizer { - - void setReadTimeout(T source, int timeout); - - void setConnectionTimeout(T source, int timeout); - - } - - enum Timeout { - - READ, CONNECTION - - } - - private static final class HttpComponentsTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(HttpComponentsMessageSender source, int timeout) { - source.setReadTimeout(timeout); - } - - @Override - public void setConnectionTimeout(HttpComponentsMessageSender source, - int timeout) { - source.setConnectionTimeout(timeout); - } - - } - - private static final class HttpUrlConnectionTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(HttpUrlConnectionMessageSender source, - int timeout) { - source.setReadTimeout(Duration.ofMillis(timeout)); - } - - @Override - public void setConnectionTimeout(HttpUrlConnectionMessageSender source, - int timeout) { - source.setConnectionTimeout(Duration.ofMillis(timeout)); - } - - } - - private static final class ClientHttpRequestTimeoutCustomizer - implements TimeoutCustomizer { - - private static final Map>> CUSTOMIZERS; - - static { - Map>> candidates = new LinkedHashMap<>(); - candidates.put( - "org.springframework.http.client.HttpComponentsClientHttpRequestFactory", - HttpComponentsClientHttpRequestFactoryTimeoutCustomizer.class); - candidates.put( - "org.springframework.http.client.OkHttp3ClientHttpRequestFactory", - OkHttp3ClientHttpRequestFactoryTimeoutCustomizer.class); - candidates.put( - "org.springframework.http.client.SimpleClientHttpRequestFactory", - SimpleClientHttpRequestFactoryTimeoutCustomizer.class); - CUSTOMIZERS = Collections.unmodifiableMap(candidates); - } - - @Override - public void setReadTimeout(ClientHttpRequestMessageSender source, - int timeout) { - ClassLoader classLoader = getClass().getClassLoader(); - customize(CUSTOMIZERS, getRequestFactory(source), Timeout.READ, timeout, - classLoader); - } - - @Override - public void setConnectionTimeout(ClientHttpRequestMessageSender source, - int timeout) { - ClassLoader classLoader = getClass().getClassLoader(); - customize(CUSTOMIZERS, getRequestFactory(source), Timeout.CONNECTION, - timeout, classLoader); - } - - private ClientHttpRequestFactory getRequestFactory( - ClientHttpRequestMessageSender source) { - ClientHttpRequestFactory requestFactory = source.getRequestFactory(); - if (!(requestFactory instanceof AbstractClientHttpRequestFactoryWrapper)) { - return requestFactory; - } - Field field = ReflectionUtils.findField( - AbstractClientHttpRequestFactoryWrapper.class, "requestFactory"); - Assert.notNull(field, "Field must not be null"); - ReflectionUtils.makeAccessible(field); - do { - requestFactory = (ClientHttpRequestFactory) ReflectionUtils - .getField(field, requestFactory); - } - while (requestFactory instanceof AbstractClientHttpRequestFactoryWrapper); - return requestFactory; - } - - private static final class SimpleClientHttpRequestFactoryTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(SimpleClientHttpRequestFactory source, - int timeout) { - source.setReadTimeout(timeout); - } - - @Override - public void setConnectionTimeout(SimpleClientHttpRequestFactory source, - int timeout) { - source.setConnectTimeout(timeout); - } - - } - - private static final class HttpComponentsClientHttpRequestFactoryTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(HttpComponentsClientHttpRequestFactory source, - int timeout) { - source.setReadTimeout(timeout); - } - - @Override - public void setConnectionTimeout( - HttpComponentsClientHttpRequestFactory source, int timeout) { - source.setConnectTimeout(timeout); - } - - } - - private static final class OkHttp3ClientHttpRequestFactoryTimeoutCustomizer - implements TimeoutCustomizer { - - @Override - public void setReadTimeout(OkHttp3ClientHttpRequestFactory source, - int timeout) { - source.setReadTimeout(timeout); - } - - @Override - public void setConnectionTimeout(OkHttp3ClientHttpRequestFactory source, - int timeout) { - source.setConnectTimeout(timeout); - } - - } - - } - - } - } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java index f619e6f999..36a6404ea6 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java @@ -22,6 +22,7 @@ import org.springframework.ws.client.core.WebServiceTemplate; * Callback interface that can be used to customize a {@link WebServiceTemplate}. * * @author Dmytro Nosan + * @since 2.1.0 */ public interface WebServiceTemplateCustomizer { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java index 5e0d4ce13f..220d07076f 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/webservices/client/package-info.java @@ -17,5 +17,4 @@ /** * Web Services client utilities. */ - package org.springframework.boot.webservices.client; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java similarity index 55% rename from spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java rename to spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java index 3d37a488f1..3edea2ae6d 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests.java @@ -22,61 +22,52 @@ import org.junit.runner.RunWith; import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; -import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.transport.WebServiceMessageSender; import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link WebServiceTemplateBuilder}. This test class check that builder will - * create ClientHttpRequestMessageSender (OkHttp3ClientHttpRequestFactory) if apache - * client is not present in the classpath + * Tests for {@link HttpWebServiceMessageSenderBuilder} when Http Components is not + * available. * - * @author Dmytro Nosan + * @author Stephane Nicoll */ @RunWith(ModifiedClassPathRunner.class) @ClassPathExclusions("httpclient-*.jar") -public class WebServiceTemplateBuilderOkHttp3ClientHttpRequestFactoryTests { +public class HttpWebServiceMessageSenderBuilderOkHttp3IntegrationTests { - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + private final HttpWebServiceMessageSenderBuilder builder = new HttpWebServiceMessageSenderBuilder(); @Test - public void build() { - - WebServiceTemplate webServiceTemplate = this.builder.build(); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); - assertThat(webServiceTemplate.getMessageSenders()[0]) - .isInstanceOf(ClientHttpRequestMessageSender.class); - - ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) webServiceTemplate - .getMessageSenders()[0]; - - assertThat(sender.getRequestFactory()) - .isInstanceOf(OkHttp3ClientHttpRequestFactory.class); - + public void buildUseOkHttp3ByDefault() { + WebServiceMessageSender messageSender = this.builder.build(); + assertOkHttp3RequestFactory(messageSender); } @Test - public void setTimeout() { - OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory(); - ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( - new BufferingClientHttpRequestFactory(factory)); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - + public void buildWithCustomTimeouts() { + WebServiceMessageSender messageSender = this.builder.setConnectionTimeout(5000) + .setReadTimeout(2000).build(); + OkHttp3ClientHttpRequestFactory factory = assertOkHttp3RequestFactory( + messageSender); OkHttpClient client = (OkHttpClient) ReflectionTestUtils.getField(factory, "client"); - assertThat(client).isNotNull(); - assertThat(client.connectTimeoutMillis()).isEqualTo(5000); assertThat(client.readTimeoutMillis()).isEqualTo(2000); + } + private OkHttp3ClientHttpRequestFactory assertOkHttp3RequestFactory( + WebServiceMessageSender messageSender) { + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) messageSender; + ClientHttpRequestFactory requestFactory = sender.getRequestFactory(); + assertThat(requestFactory).isInstanceOf(OkHttp3ClientHttpRequestFactory.class); + return (OkHttp3ClientHttpRequestFactory) requestFactory; } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java new file mode 100644 index 0000000000..361927ff29 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java @@ -0,0 +1,71 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; +import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link HttpWebServiceMessageSenderBuilder} when no preferred HTTP clients are + * available + * + * @author Stephane Nicoll + */ +@RunWith(ModifiedClassPathRunner.class) +@ClassPathExclusions({ "httpclient-*.jar", "okhttp*.jar" }) +public class HttpWebServiceMessageSenderBuilderSimpleIntegrationTests { + + private final HttpWebServiceMessageSenderBuilder builder = new HttpWebServiceMessageSenderBuilder(); + + @Test + public void buildUseUseSimpleClientByDefault() { + WebServiceMessageSender messageSender = this.builder.build(); + assertSimpleClientRequestFactory(messageSender); + } + + @Test + public void buildWithCustomTimeouts() { + WebServiceMessageSender messageSender = this.builder.setConnectionTimeout(5000) + .setReadTimeout(2000).build(); + SimpleClientHttpRequestFactory requestFactory = assertSimpleClientRequestFactory( + messageSender); + assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) + .isEqualTo(5000); + assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) + .isEqualTo(2000); + } + + private SimpleClientHttpRequestFactory assertSimpleClientRequestFactory( + WebServiceMessageSender messageSender) { + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) messageSender; + ClientHttpRequestFactory requestFactory = sender.getRequestFactory(); + assertThat(requestFactory).isInstanceOf(SimpleClientHttpRequestFactory.class); + return (SimpleClientHttpRequestFactory) requestFactory; + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java new file mode 100644 index 0000000000..e844882a1f --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012-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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.webservices.client; + +import org.apache.http.client.config.RequestConfig; +import org.junit.Test; + +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.transport.WebServiceMessageSender; +import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link HttpWebServiceMessageSenderBuilder}. + * + * @author Stephane Nicoll + */ +public class HttpWebServiceMessageSenderBuilderTests { + + @Test + public void buildWithRequestFactorySupplier() { + ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class); + ClientHttpRequestMessageSender messageSender = build( + new HttpWebServiceMessageSenderBuilder() + .requestFactory(() -> requestFactory)); + assertThat(messageSender.getRequestFactory()).isSameAs(requestFactory); + } + + @Test + public void buildWithReadAndConnectTimeout() { + ClientHttpRequestMessageSender messageSender = build( + new HttpWebServiceMessageSenderBuilder() + .requestFactory(SimpleClientHttpRequestFactory::new) + .setConnectionTimeout(5000).setReadTimeout(2000)); + SimpleClientHttpRequestFactory requestFactory = (SimpleClientHttpRequestFactory) messageSender + .getRequestFactory(); + assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) + .isEqualTo(5000); + assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) + .isEqualTo(2000); + } + + @Test + public void buildUsesHttpComponentsBydefault() { + ClientHttpRequestMessageSender messageSender = build( + new HttpWebServiceMessageSenderBuilder().setConnectionTimeout(5000) + .setReadTimeout(2000)); + ClientHttpRequestFactory requestFactory = messageSender.getRequestFactory(); + assertThat(requestFactory) + .isInstanceOf(HttpComponentsClientHttpRequestFactory.class); + RequestConfig requestConfig = (RequestConfig) ReflectionTestUtils + .getField(requestFactory, "requestConfig"); + assertThat(requestConfig).isNotNull(); + assertThat(requestConfig.getConnectTimeout()).isEqualTo(5000); + assertThat(requestConfig.getSocketTimeout()).isEqualTo(2000); + } + + private ClientHttpRequestMessageSender build( + HttpWebServiceMessageSenderBuilder builder) { + WebServiceMessageSender messageSender = builder.build(); + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + return ((ClientHttpRequestMessageSender) messageSender); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java deleted file mode 100644 index 8ae3040b95..0000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderCustomsMessageSenderTests.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2012-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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.webservices.client; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; - -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.ws.transport.WebServiceMessageSender; -import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; - -/** - * Tests for - * {@link org.springframework.boot.webservices.client.WebServiceTemplateBuilder}. - * - * @author Dmytro Nosan - */ -public class WebServiceTemplateBuilderCustomsMessageSenderTests { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void unknownSenderReadTimeout() { - this.thrown.expect(IllegalStateException.class); - this.thrown.expectMessage("with 'readTimeout'. Please use a custom customizer."); - this.thrown.expectMessage("There is no way to customize"); - - this.builder.setReadTimeout(3000).setWebServiceMessageSender( - () -> Mockito.mock(WebServiceMessageSender.class)).build(); - } - - @Test - public void unknownSenderConnectionTimeout() { - this.thrown.expect(IllegalStateException.class); - this.thrown.expectMessage( - "with 'connectionTimeout'. Please use a custom customizer."); - this.thrown.expectMessage("There is no way to customize"); - - this.builder.setConnectionTimeout(3000).setWebServiceMessageSender( - () -> Mockito.mock(WebServiceMessageSender.class)).build(); - } - - @Test - public void unknownRequestFactoryReadTimeout() { - this.thrown.expect(IllegalStateException.class); - this.thrown.expectMessage("with 'readTimeout'. Please use a custom customizer."); - this.thrown.expectMessage("There is no way to customize"); - - this.builder.setReadTimeout(3000) - .setWebServiceMessageSender(() -> new ClientHttpRequestMessageSender( - Mockito.mock(ClientHttpRequestFactory.class))) - .build(); - } - - @Test - public void unknownRequestFactoryConnectionTimeout() { - this.thrown.expect(IllegalStateException.class); - this.thrown.expectMessage( - "with 'connectionTimeout'. Please use a custom customizer."); - this.thrown.expectMessage("There is no way to customize"); - - this.builder.setConnectionTimeout(3000) - .setWebServiceMessageSender(() -> new ClientHttpRequestMessageSender( - Mockito.mock(ClientHttpRequestFactory.class))) - .build(); - } - - @Test - public void shouldBuildWithoutTimeouts() { - this.builder.setWebServiceMessageSender( - () -> Mockito.mock(WebServiceMessageSender.class)).build(); - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java deleted file mode 100644 index f2cafa15c7..0000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2012-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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.webservices.client; - -import org.apache.http.client.config.RequestConfig; -import org.junit.Test; - -import org.springframework.http.client.BufferingClientHttpRequestFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link WebServiceTemplateBuilder}. - * - * @author Dmytro Nosan - */ -public class WebServiceTemplateBuilderHttpComponentsClientHttpRequestFactoryTests { - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void setTimeout() { - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); - ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( - new BufferingClientHttpRequestFactory(factory)); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - - RequestConfig requestConfig = (RequestConfig) ReflectionTestUtils - .getField(factory, "requestConfig"); - assertThat(requestConfig).isNotNull(); - assertThat(requestConfig.getConnectTimeout()).isEqualTo(5000); - assertThat(requestConfig.getSocketTimeout()).isEqualTo(2000); - - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java deleted file mode 100644 index 82f08a27de..0000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpComponentsMessageSenderTests.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2012-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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.webservices.client; - -import org.apache.http.client.HttpClient; -import org.apache.http.params.HttpConnectionParams; -import org.junit.Test; - -import org.springframework.ws.client.core.WebServiceTemplate; -import org.springframework.ws.transport.http.HttpComponentsMessageSender; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for - * {@link org.springframework.boot.webservices.client.WebServiceTemplateBuilder}. This - * test class check that builder will create HttpComponents by default if apache client is - * present in the classpath. - * - * @author Dmytro Nosan - */ -@SuppressWarnings("deprecation") -public class WebServiceTemplateBuilderHttpComponentsMessageSenderTests { - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void build() { - WebServiceTemplate webServiceTemplate = new WebServiceTemplateBuilder().build(); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); - - assertThat(webServiceTemplate.getMessageSenders()[0]) - .isInstanceOf(HttpComponentsMessageSender.class); - - } - - @Test - public void setTimeout() { - HttpComponentsMessageSender sender = new HttpComponentsMessageSender(); - HttpClient httpClient = sender.getHttpClient(); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - - assertThat(HttpConnectionParams.getConnectionTimeout(httpClient.getParams())) - .isEqualTo(5000); - assertThat(HttpConnectionParams.getSoTimeout(httpClient.getParams())) - .isEqualTo(2000); - - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java deleted file mode 100644 index 3468091f6e..0000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2012-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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.webservices.client; - -import java.time.Duration; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions; -import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.ws.client.core.WebServiceTemplate; -import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link WebServiceTemplateBuilder}. This test class check that builder will - * create HttpUrlConnectionMessageSender If Ok-http and Apache client are not present in - * the classpath. - * - * @author Dmytro Nosan - */ -@RunWith(ModifiedClassPathRunner.class) -@ClassPathExclusions({ "httpclient-*.jar", "okhttp-*.jar" }) -public class WebServiceTemplateBuilderHttpUrlConnectionMessageSenderTests { - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void build() { - WebServiceTemplate webServiceTemplate = this.builder.build(); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); - - assertThat(webServiceTemplate.getMessageSenders()[0]) - .isInstanceOf(HttpUrlConnectionMessageSender.class); - - } - - @Test - public void setTimeout() { - HttpUrlConnectionMessageSender sender = new HttpUrlConnectionMessageSender(); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - - assertThat(ReflectionTestUtils.getField(sender, "connectionTimeout")) - .isEqualTo(Duration.ofMillis(5000)); - assertThat(ReflectionTestUtils.getField(sender, "readTimeout")) - .isEqualTo(Duration.ofMillis(2000)); - - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java deleted file mode 100644 index e2f3c0a5c3..0000000000 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2012-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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.webservices.client; - -import org.junit.Test; - -import org.springframework.http.client.BufferingClientHttpRequestFactory; -import org.springframework.http.client.SimpleClientHttpRequestFactory; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link WebServiceTemplateBuilder}. - * - * @author Dmytro Nosan - */ -public class WebServiceTemplateBuilderSimpleClientHttpRequestFactoryTests { - - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - - @Test - public void setTimeout() { - SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); - ClientHttpRequestMessageSender sender = new ClientHttpRequestMessageSender( - new BufferingClientHttpRequestFactory(factory)); - - this.builder.setConnectionTimeout(5000).setReadTimeout(2000) - .setWebServiceMessageSender(() -> sender).build(); - - assertThat(ReflectionTestUtils.getField(factory, "connectTimeout")) - .isEqualTo(5000); - assertThat(ReflectionTestUtils.getField(factory, "readTimeout")).isEqualTo(2000); - - } - -} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java index ffdffd4040..82480b57b5 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java @@ -19,300 +19,332 @@ package org.springframework.boot.webservices.client; import java.net.URI; import java.util.Collection; import java.util.Collections; -import java.util.function.Supplier; +import java.util.Set; -import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXTransformerFactory; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; -import org.springframework.oxm.jaxb.Jaxb2Marshaller; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; +import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.FaultMessageResolver; import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.client.support.destination.DestinationProvider; import org.springframework.ws.client.support.interceptor.ClientInterceptor; -import org.springframework.ws.soap.client.core.SoapFaultMessageResolver; -import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; import org.springframework.ws.transport.WebServiceMessageSender; import org.springframework.ws.transport.http.ClientHttpRequestMessageSender; import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; /** * Tests for {@link WebServiceTemplateBuilder}. * + * @author Stephane Nicoll * @author Dmytro Nosan */ public class WebServiceTemplateBuilderTests { - private WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); + private final WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder(); - @Test - public void addInterceptors() { - ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); - ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + @Rule + public ExpectedException thrown = ExpectedException.none(); - WebServiceTemplate webServiceTemplate = this.builder.addInterceptors(f1) - .addInterceptors(f2).build(); + @Mock + private WebServiceMessageSender messageSender; - assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f1, - f2); + @Mock + private ClientInterceptor interceptor; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); } @Test - public void addInterceptorsCollection() { - ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); - ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + public void createWithCustomizersShouldApplyCustomizers() { + WebServiceTemplateCustomizer customizer = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplate template = new WebServiceTemplateBuilder(customizer).build(); + verify(customizer).customize(template); + } + @Test + public void buildShouldDetectHttpMessageSender() { + WebServiceTemplate webServiceTemplate = this.builder.build(); + assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); + WebServiceMessageSender messageSender = webServiceTemplate.getMessageSenders()[0]; + assertHttpComponentsRequestFactory(messageSender); + } + + @Test + public void detectHttpMessageSenderWhenFalseShouldDisableDetection() { WebServiceTemplate webServiceTemplate = this.builder - .addInterceptors(Collections.singletonList(f1)) - .addInterceptors(Collections.singleton(f2)).build(); - - assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f1, - f2); - - } - - @Test - public void setInterceptors() { - ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); - ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); - - WebServiceTemplate webServiceTemplate = this.builder.setInterceptors(f1) - .setInterceptors(f2).build(); - - assertThat(webServiceTemplate.getInterceptors()).doesNotContain(f1).contains(f2); - } - - @Test - public void setInterceptorsCollection() { - ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); - ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); - - WebServiceTemplate webServiceTemplate = this.builder - .setInterceptors(Collections.singletonList(f1)) - .setInterceptors(Collections.singleton(f2)).build(); - - assertThat(webServiceTemplate.getInterceptors()).doesNotContain(f1).contains(f2); - - } - - @Test - public void addCustomizers() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - WebServiceTemplateCustomizer customizer = (ws) -> ws - .setMarshaller(jaxb2Marshaller); - WebServiceTemplateCustomizer customizer1 = (ws) -> ws - .setUnmarshaller(jaxb2Marshaller); - - WebServiceTemplate webServiceTemplate = this.builder.addCustomizers(customizer) - .addCustomizers(customizer1).build(); - - assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); - - } - - @Test - public void addCustomizersCollection() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - WebServiceTemplateCustomizer customizer = (ws) -> ws - .setMarshaller(jaxb2Marshaller); - WebServiceTemplateCustomizer customizer1 = (ws) -> ws - .setUnmarshaller(jaxb2Marshaller); - - WebServiceTemplate webServiceTemplate = this.builder - .addCustomizers(Collections.singleton(customizer)) - .addCustomizers(Collections.singletonList(customizer1)).build(); - - assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); - } - - @Test - public void setCustomizers() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - WebServiceTemplateCustomizer customizer = (ws) -> ws - .setMarshaller(jaxb2Marshaller); - WebServiceTemplateCustomizer customizer1 = (ws) -> ws - .setUnmarshaller(jaxb2Marshaller); - - WebServiceTemplate webServiceTemplate = this.builder.setCustomizers(customizer) - .setCustomizers(customizer1).build(); - - assertThat(webServiceTemplate.getMarshaller()).isNull(); - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); - - } - - @Test - public void setCustomizersCollection() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - WebServiceTemplateCustomizer customizer = (ws) -> ws - .setMarshaller(jaxb2Marshaller); - WebServiceTemplateCustomizer customizer1 = (ws) -> ws - .setUnmarshaller(jaxb2Marshaller); - - WebServiceTemplate webServiceTemplate = this.builder - .setCustomizers(Collections.singleton(customizer)) - .setCustomizers(Collections.singletonList(customizer1)).build(); - - assertThat(webServiceTemplate.getMarshaller()).isNull(); - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Marshaller); - } - - @Test - public void addWebServiceMessageSenders() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); - - WebServiceTemplate webServiceTemplate = this.builder - .addWebServiceMessageSenders(Collections.singleton(() -> sender)) - .addWebServiceMessageSenders(Collections.singletonList(() -> sender1)) - .build(); - - assertThat(webServiceTemplate.getMessageSenders()) - .containsExactlyInAnyOrder(sender, sender1); - } - - @Test - public void setWebServiceMessageSenders() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); - - WebServiceTemplate webServiceTemplate = this.builder - .setWebServiceMessageSenders(Collections.singleton(() -> sender)) - .setWebServiceMessageSenders(Collections.singletonList(() -> sender1)) - .build(); - - assertThat(webServiceTemplate.getMessageSenders()).doesNotContain(sender) - .contains(sender1); - - } - - @Test - public void addWebServiceMessageSenderClass() { - - WebServiceTemplate webServiceTemplate = this.builder - .addWebServiceMessageSender(ClientHttpRequestMessageSender.class) - .addWebServiceMessageSender(HttpUrlConnectionMessageSender.class).build(); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(2); - - assertThat(webServiceTemplate.getMessageSenders()[0]) - .isInstanceOf(ClientHttpRequestMessageSender.class); - assertThat(webServiceTemplate.getMessageSenders()[1]) - .isInstanceOf(HttpUrlConnectionMessageSender.class); - } - - @Test - public void setWebServiceMessageSenderClass() { - - WebServiceTemplate webServiceTemplate = this.builder - .setWebServiceMessageSender(ClientHttpRequestMessageSender.class) - .setWebServiceMessageSender(HttpUrlConnectionMessageSender.class).build(); - + .detectHttpMessageSender(false).build(); assertThat(webServiceTemplate.getMessageSenders()).hasSize(1); assertThat(webServiceTemplate.getMessageSenders()[0]) .isInstanceOf(HttpUrlConnectionMessageSender.class); - } @Test - public void addWebServiceMessageSender() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); - - WebServiceTemplate webServiceTemplate = this.builder - .addWebServiceMessageSender(() -> sender) - .addWebServiceMessageSender(() -> sender1).build(); - - assertThat(webServiceTemplate.getMessageSenders()) - .containsExactlyInAnyOrder(sender, sender1); + public void messageSendersWhenSendersAreAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("MessageSenders must not be null"); + this.builder.messageSenders((WebServiceMessageSender[]) null); } @Test - public void setWebServiceMessageSender() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceMessageSender sender1 = Mockito.mock(WebServiceMessageSender.class); + public void messageSendersCollectionWhenSendersAreAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("MessageSenders must not be null"); + this.builder.messageSenders((Collection) null); + } - WebServiceTemplate webServiceTemplate = this.builder - .setWebServiceMessageSender(() -> sender) - .setWebServiceMessageSender(() -> sender1).build(); + @Test + public void messageSendersShouldApply() { + WebServiceTemplate template = this.builder.messageSenders(this.messageSender) + .build(); + assertThat(template.getMessageSenders()).containsOnly(this.messageSender); + } - assertThat(webServiceTemplate.getMessageSenders()).doesNotContain(sender) - .contains(sender1); + @Test + public void messageSendersShouldReplaceExisting() { + WebServiceTemplate template = this.builder + .messageSenders(new ClientHttpRequestMessageSender()) + .messageSenders(this.messageSender).build(); + assertThat(template.getMessageSenders()).containsOnly(this.messageSender); + } + @Test + public void additionalMessageSendersWhenSendersAreAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("MessageSenders must not be null"); + this.builder.additionalMessageSenders((WebServiceMessageSender[]) null); + } + + @Test + public void additionalMessageSendersCollectionWhenSendersAreAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("MessageSenders must not be null"); + this.builder.additionalMessageSenders( + (Collection) null); + } + + @Test + public void additionalMessageSendersShouldAddToExisting() { + ClientHttpRequestMessageSender httpMessageSender = new ClientHttpRequestMessageSender(); + WebServiceTemplate template = this.builder.messageSenders(httpMessageSender) + .additionalMessageSenders(this.messageSender).build(); + assertThat(template.getMessageSenders()).containsOnly(httpMessageSender, + this.messageSender); + } + + @Test + public void additionalMessageSendersShouldKeepDetectedHttpMessageSender() { + WebServiceTemplate template = this.builder + .additionalMessageSenders(this.messageSender).build(); + assertThat(template.getMessageSenders()).contains(this.messageSender); + assertThat(template.getMessageSenders()).hasSize(2); + } + + @Test + public void interceptorsWhenInterceptorsAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Interceptors must not be null"); + this.builder.interceptors((ClientInterceptor[]) null); + } + + @Test + public void interceptorsCollectionWhenInterceptorsAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Interceptors must not be null"); + this.builder.interceptors((Collection) null); + } + + @Test + public void interceptorsShouldApply() { + WebServiceTemplate template = this.builder.interceptors(this.interceptor).build(); + assertThat(template.getInterceptors()).containsOnly(this.interceptor); + } + + @Test + public void interceptorsShouldReplaceExisting() { + WebServiceTemplate template = this.builder + .interceptors(mock(ClientInterceptor.class)) + .interceptors(Collections.singleton(this.interceptor)).build(); + assertThat(template.getInterceptors()).containsOnly(this.interceptor); + } + + @Test + public void additionalInterceptorsWhenInterceptorsAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Interceptors must not be null"); + this.builder.additionalInterceptors((ClientInterceptor[]) null); + } + + @Test + public void additionalInterceptorsCollectionWhenInterceptorsAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Interceptors must not be null"); + this.builder.additionalInterceptors((Set) null); + } + + @Test + public void additionalInterceptorsShouldAddToExisting() { + ClientInterceptor interceptor = mock(ClientInterceptor.class); + WebServiceTemplate template = this.builder.interceptors(interceptor) + .additionalInterceptors(this.interceptor).build(); + assertThat(template.getInterceptors()).containsOnly(interceptor, + this.interceptor); + } + + @Test + public void additionalInterceptorsShouldAddToExistingWebServiceTemplate() { + ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); + ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); + WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); + webServiceTemplate.setInterceptors(new ClientInterceptor[] { f1 }); + this.builder.additionalInterceptors(f2).configure(webServiceTemplate); + assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f2, + f1); + } + + @Test + public void customizersWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Customizers must not be null"); + this.builder.customizers((WebServiceTemplateCustomizer[]) null); + } + + @Test + public void customizersCollectionWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Customizers must not be null"); + this.builder + .customizers((Collection) null); + } + + @Test + public void customizersShouldApply() { + WebServiceTemplateCustomizer customizer = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplate template = this.builder.customizers(customizer).build(); + verify(customizer).customize(template); + } + + @Test + public void customizersShouldBeAppliedLast() { + WebServiceTemplate template = spy(new WebServiceTemplate()); + this.builder + .additionalCustomizers(((webServiceTemplate) -> verify(webServiceTemplate) + .setMessageSenders(any()))); + this.builder.configure(template); + } + + @Test + public void customizersShouldReplaceExisting() { + WebServiceTemplateCustomizer customizer1 = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplateCustomizer customizer2 = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplate template = this.builder.customizers(customizer1) + .customizers(Collections.singleton(customizer2)).build(); + verifyZeroInteractions(customizer1); + verify(customizer2).customize(template); + } + + @Test + public void additionalCustomizersWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Customizers must not be null"); + this.builder.additionalCustomizers((WebServiceTemplateCustomizer[]) null); + } + + @Test + public void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Customizers must not be null"); + this.builder.additionalCustomizers( + (Collection) null); + } + + @Test + public void additionalCustomizersShouldAddToExisting() { + WebServiceTemplateCustomizer customizer1 = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplateCustomizer customizer2 = mock( + WebServiceTemplateCustomizer.class); + WebServiceTemplate template = this.builder.customizers(customizer1) + .additionalCustomizers(customizer2).build(); + verify(customizer1).customize(template); + verify(customizer2).customize(template); } @Test public void setCheckConnectionForFault() { - MockWebServiceTemplate webServiceTemplate = this.builder - .setCheckConnectionForFault(false).build(MockWebServiceTemplate.class); - - assertThat(webServiceTemplate.isCheckConnectionForFault()).isFalse(); + WebServiceTemplate template = mock(WebServiceTemplate.class); + this.builder.setCheckConnectionForFault(false).configure(template); + verify(template).setCheckConnectionForFault(false); } @Test public void setCheckConnectionForError() { - - MockWebServiceTemplate webServiceTemplate = this.builder - .setCheckConnectionForError(false).build(MockWebServiceTemplate.class); - - assertThat(webServiceTemplate.isCheckConnectionForError()).isFalse(); + WebServiceTemplate template = mock(WebServiceTemplate.class); + this.builder.setCheckConnectionForError(false).configure(template); + verify(template).setCheckConnectionForError(false); } @Test public void setTransformerFactoryClass() { - MockWebServiceTemplate webServiceTemplate = this.builder - .setTransformerFactoryClass(SAXTransformerFactory.class) - .build(MockWebServiceTemplate.class); - - assertThat(webServiceTemplate.getTransformerFactoryClass()) - .isEqualTo(SAXTransformerFactory.class); - + WebServiceTemplate template = mock(WebServiceTemplate.class); + this.builder.setTransformerFactoryClass(SAXTransformerFactory.class) + .configure(template); + verify(template).setTransformerFactoryClass(SAXTransformerFactory.class); } @Test public void setWebServiceMessageFactory() { - - SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(); - - WebServiceTemplate webServiceTemplate = this.builder + WebServiceMessageFactory messageFactory = mock(WebServiceMessageFactory.class); + WebServiceTemplate template = this.builder .setWebServiceMessageFactory(messageFactory).build(); - - assertThat(webServiceTemplate.getMessageFactory()).isEqualTo(messageFactory); - + assertThat(template.getMessageFactory()).isEqualTo(messageFactory); } @Test public void setMarshaller() { - Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller(); - - WebServiceTemplate webServiceTemplate = this.builder - .setMarshaller(jaxb2Marshaller).build(); - assertThat(webServiceTemplate.getMarshaller()).isEqualTo(jaxb2Marshaller); + Marshaller marshaller = mock(Marshaller.class); + WebServiceTemplate template = this.builder.setMarshaller(marshaller).build(); + assertThat(template.getMarshaller()).isEqualTo(marshaller); } @Test public void setUnmarshaller() { - Jaxb2Marshaller jaxb2Unmarshaller = new Jaxb2Marshaller(); - - WebServiceTemplate webServiceTemplate = this.builder - .setUnmarshaller(jaxb2Unmarshaller).build(); - - assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(jaxb2Unmarshaller); + Unmarshaller unmarshaller = mock(Unmarshaller.class); + WebServiceTemplate webServiceTemplate = this.builder.setUnmarshaller(unmarshaller) + .build(); + assertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(unmarshaller); } @Test public void setFaultMessageResolver() { - - FaultMessageResolver faultMessageResolver = new SoapFaultMessageResolver(); + FaultMessageResolver faultMessageResolver = mock(FaultMessageResolver.class); WebServiceTemplate webServiceTemplate = this.builder .setFaultMessageResolver(faultMessageResolver).build(); - assertThat(webServiceTemplate.getFaultMessageResolver()) .isEqualTo(faultMessageResolver); } @@ -320,201 +352,29 @@ public class WebServiceTemplateBuilderTests { @Test public void setDefaultUri() { URI uri = URI.create("http://localhost:8080"); - WebServiceTemplate webServiceTemplate = this.builder.setDefaultUri(uri.toString()) .build(); - assertThat(webServiceTemplate.getDestinationProvider().getDestination()) .isEqualTo(uri); - } @Test public void setDestinationProvider() { - URI uri = URI.create("http://localhost:8080"); - + DestinationProvider destinationProvider = () -> URI + .create("http://localhost:8080"); WebServiceTemplate webServiceTemplate = this.builder - .setDestinationProvider(() -> uri).build(); - - assertThat(webServiceTemplate.getDestinationProvider().getDestination()) - .isEqualTo(uri); - + .setDestinationProvider(destinationProvider).build(); + assertThat(webServiceTemplate.getDestinationProvider()) + .isEqualTo(destinationProvider); } - @Test - public void shouldNotOverrideDefaultSender() { - WebServiceMessageSender sender = Mockito.mock(WebServiceMessageSender.class); - WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); - webServiceTemplate.setMessageSender(sender); - - this.builder.detectWebServiceMessageSender(false).configure(webServiceTemplate); - - assertThat(webServiceTemplate.getMessageSenders()).hasSize(1).contains(sender); - - } - - @Test - public void addInterceptorsToExistingWebServiceTemplate() { - ClientInterceptor f1 = Mockito.mock(ClientInterceptor.class); - ClientInterceptor f2 = Mockito.mock(ClientInterceptor.class); - - WebServiceTemplate webServiceTemplate = new WebServiceTemplate(); - webServiceTemplate.setInterceptors(new ClientInterceptor[] { f1 }); - - this.builder.addInterceptors(f2).configure(webServiceTemplate); - - assertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f2, - f1); - } - - @Test(expected = IllegalArgumentException.class) - public void setInterceptorsArrayNull() { - this.builder.setInterceptors((ClientInterceptor[]) null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setInterceptorsCollectionNull() { - this.builder.setInterceptors((Collection) null) - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void addInterceptorsArrayNull() { - this.builder.addInterceptors((ClientInterceptor[]) null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void addInterceptorsCollectionNull() { - this.builder.addInterceptors((Collection) null) - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setCustomizersArrayNull() { - this.builder.setCustomizers((WebServiceTemplateCustomizer[]) null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setCustomizersCollectionNull() { - this.builder - .setCustomizers((Collection) null) - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void addCustomizersArrayNull() { - this.builder - .addCustomizers((Collection) null) - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void addCustomizersCollectionNull() { - this.builder - .addCustomizers((Collection) null) - .build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setWebServiceMessageSendersNull() { - this.builder.setWebServiceMessageSenders(null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void addWebServiceMessageSendersNull() { - this.builder.addWebServiceMessageSenders(null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setWebServiceMessageSenderClassNull() { - this.builder.setWebServiceMessageSender( - (Class) null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void addWebServiceMessageSenderClassNull() { - this.builder.addWebServiceMessageSender( - (Class) null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setWebServiceMessageSenderSupplierNull() { - this.builder.setWebServiceMessageSender( - (Supplier) null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void addWebServiceMessageSenderSupplierNull() { - this.builder.addWebServiceMessageSender( - (Supplier) null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setWebServiceMessageFactoryNull() { - this.builder.setWebServiceMessageFactory(null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setUnmarshallerNull() { - this.builder.setUnmarshaller(null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setMarshallerNull() { - this.builder.setMarshaller(null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setTransformerFactoryClassNull() { - this.builder.setTransformerFactoryClass(null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setDefaultUriNull() { - this.builder.setDefaultUri(null).build(); - } - - @Test(expected = IllegalArgumentException.class) - public void setDestinationProviderNull() { - this.builder.setDestinationProvider(null).build(); - } - - private static class MockWebServiceTemplate extends WebServiceTemplate { - - private boolean checkConnectionForError; - - private boolean checkConnectionForFault; - - private Class transformerFactoryClass; - - boolean isCheckConnectionForError() { - return this.checkConnectionForError; - } - - @Override - public void setCheckConnectionForError(boolean checkConnectionForError) { - this.checkConnectionForError = checkConnectionForError; - } - - boolean isCheckConnectionForFault() { - return this.checkConnectionForFault; - } - - @Override - public void setCheckConnectionForFault(boolean checkConnectionForFault) { - this.checkConnectionForFault = checkConnectionForFault; - } - - Class getTransformerFactoryClass() { - return this.transformerFactoryClass; - } - - @Override - public void setTransformerFactoryClass( - Class transformerFactoryClass) { - this.transformerFactoryClass = transformerFactoryClass; - } - + private void assertHttpComponentsRequestFactory( + WebServiceMessageSender messageSender) { + assertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class); + ClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) messageSender; + ClientHttpRequestFactory requestFactory = sender.getRequestFactory(); + assertThat(requestFactory) + .isInstanceOf(HttpComponentsClientHttpRequestFactory.class); } }