From 50ac603d6c14563c1c46330be5915d32c8570fa5 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 21 Feb 2020 16:47:42 -0500 Subject: [PATCH] GH-3180: Add encoding-mode to WS outbound gateway (#3191) * GH-3180: Add encoding-mode to WS outbound gateway Fixes https://github.com/spring-projects/spring-integration/issues/3180 * Deprecate `encode-uri` in favor of newly introduced `encoding-mode` * Add new property to XML and DSL configurations * Fix tests according a new behavior * Document the feature * Fix docs for deprecated `encode-uri` * Mention also WS from `http.adoc` * * Fix typos in docs --- .../ws/AbstractWebServiceOutboundGateway.java | 69 +++++++++++-------- .../WebServiceOutboundGatewayParser.java | 12 ++-- .../ws/dsl/BaseWsOutboundGatewaySpec.java | 19 ++--- .../ws/config/spring-integration-ws.xsd | 22 +++++- .../ws/config/UriVariableTests-context.xml | 1 + .../ws/config/UriVariableTests.java | 13 ++-- ...viceOutboundGatewayParserTests-context.xml | 2 +- .../WebServiceOutboundGatewayParserTests.java | 45 +++++++----- .../integration/ws/dsl/WsDslTests.java | 19 +++-- src/reference/asciidoc/http.adoc | 4 +- src/reference/asciidoc/whats-new.adoc | 2 + src/reference/asciidoc/ws.adoc | 14 ++-- 12 files changed, 135 insertions(+), 87 deletions(-) diff --git a/spring-integration-ws/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java b/spring-integration-ws/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java index 6b82fec441..49f64213fc 100644 --- a/spring-integration-ws/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java +++ b/spring-integration-ws/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java @@ -18,7 +18,6 @@ package org.springframework.integration.ws; import java.io.IOException; import java.net.URI; -import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; @@ -35,8 +34,7 @@ import org.springframework.messaging.MessageDeliveryException; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.FaultMessageResolver; @@ -60,11 +58,13 @@ import org.springframework.xml.transform.TransformerObjectSupport; */ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyProducingMessageHandler { + protected final DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory(); // NOSONAR - final + private final String uri; private final DestinationProvider destinationProvider; - private final Map uriVariableExpressions = new HashMap(); + private final Map uriVariableExpressions = new HashMap<>(); private StandardEvaluationContext evaluationContext; @@ -74,8 +74,6 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro private boolean ignoreEmptyResponses = true; - private boolean encodeUri = true; - private SoapHeaderMapper headerMapper = new DefaultSoapHeaderMapper(); private boolean webServiceTemplateExplicitlySet; @@ -89,6 +87,7 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro public AbstractWebServiceOutboundGateway(DestinationProvider destinationProvider, WebServiceMessageFactory messageFactory) { + Assert.notNull(destinationProvider, "DestinationProvider must not be null"); this.webServiceTemplate = new WebServiceTemplate(messageFactory); this.destinationProvider = destinationProvider; @@ -99,6 +98,7 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro } public void setHeaderMapper(SoapHeaderMapper headerMapper) { + Assert.notNull(headerMapper, "'headerMapper' must not be null"); this.headerMapper = headerMapper; } @@ -120,13 +120,29 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro * @param encodeUri true if the URI should be encoded. * @see org.springframework.web.util.UriComponentsBuilder * @since 4.1 + * @deprecated since 5.3 in favor of {@link #setEncodingMode} */ + @Deprecated public void setEncodeUri(boolean encodeUri) { - this.encodeUri = encodeUri; + setEncodingMode( + encodeUri + ? DefaultUriBuilderFactory.EncodingMode.TEMPLATE_AND_VALUES + : DefaultUriBuilderFactory.EncodingMode.NONE); + } + + /** + * Set the encoding mode to use. + * By default this is set to {@link DefaultUriBuilderFactory.EncodingMode#TEMPLATE_AND_VALUES}. + * @param encodingMode the mode to use for uri encoding + * @since 5.3 + */ + public void setEncodingMode(DefaultUriBuilderFactory.EncodingMode encodingMode) { + Assert.notNull(encodingMode, "'encodingMode' must not be null"); + this.uriFactory.setEncodingMode(encodingMode); } public void setReplyChannel(MessageChannel replyChannel) { - this.setOutputChannel(replyChannel); + setOutputChannel(replyChannel); } /** @@ -200,40 +216,33 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro @Override public final Object handleRequestMessage(Message requestMessage) { - URI uriWithVariables = null; - try { - uriWithVariables = this.prepareUri(requestMessage); - } - catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } + URI uriWithVariables = prepareUri(requestMessage); if (uriWithVariables == null) { throw new MessageDeliveryException(requestMessage, "Failed to determine URI for " + "Web Service request in outbound gateway: " + this.getComponentName()); } - Object responsePayload = this.doHandle(uriWithVariables.toString(), requestMessage, this.requestCallback); - if (responsePayload != null) { - boolean shouldIgnore = (this.ignoreEmptyResponses - && responsePayload instanceof String && !StringUtils.hasText((String) responsePayload)); - if (!shouldIgnore) { - return responsePayload; - } + Object responsePayload = doHandle(uriWithVariables.toString(), requestMessage, this.requestCallback); + if (responsePayload != null && !(this.ignoreEmptyResponses + && responsePayload instanceof String + && !StringUtils.hasText((String) responsePayload))) { + + return responsePayload; } return null; } - private URI prepareUri(Message requestMessage) throws URISyntaxException { + private URI prepareUri(Message requestMessage) { if (this.destinationProvider != null) { return this.destinationProvider.getDestination(); } - Map uriVariables = ExpressionEvalMap.from(this.uriVariableExpressions) - .usingEvaluationContext(this.evaluationContext) - .withRoot(requestMessage) - .build(); + Map uriVariables = + ExpressionEvalMap.from(this.uriVariableExpressions) + .usingEvaluationContext(this.evaluationContext) + .withRoot(requestMessage) + .build(); - UriComponents uriComponents = UriComponentsBuilder.fromUriString(this.uri).buildAndExpand(uriVariables); - return this.encodeUri ? uriComponents.toUri() : new URI(uriComponents.toUriString()); + return this.uriFactory.expand(this.uri, uriVariables); } @@ -282,7 +291,7 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro if (resultObject != null && message instanceof SoapMessage) { Map mappedMessageHeaders = AbstractWebServiceOutboundGateway.this.headerMapper.toHeadersFromReply((SoapMessage) message); - return AbstractWebServiceOutboundGateway.this.getMessageBuilderFactory() + return getMessageBuilderFactory() .withPayload(resultObject) .copyHeaders(mappedMessageHeaders) .build(); diff --git a/spring-integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java b/spring-integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java index e46a50c2c9..2b00c68f30 100644 --- a/spring-integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java +++ b/spring-integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,7 +52,7 @@ public class WebServiceOutboundGatewayParser extends AbstractOutboundGatewayPars @Override protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(this.getGatewayClassName(element)); + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(getGatewayClassName(element)); String uri = element.getAttribute("uri"); String destinationProvider = element.getAttribute("destination-provider"); List uriVariableElements = DomUtils.getChildElementsByTagName(element, "uri-variable"); @@ -70,7 +70,7 @@ public class WebServiceOutboundGatewayParser extends AbstractOutboundGatewayPars else { builder.addConstructorArgValue(uri); if (!CollectionUtils.isEmpty(uriVariableElements)) { - ManagedMap uriVariableExpressions = new ManagedMap(); + ManagedMap uriVariableExpressions = new ManagedMap<>(); for (Element uriVariableElement : uriVariableElements) { String name = uriVariableElement.getAttribute("name"); String expression = uriVariableElement.getAttribute("expression"); @@ -87,9 +87,11 @@ public class WebServiceOutboundGatewayParser extends AbstractOutboundGatewayPars IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "ignore-empty-responses"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "encode-uri"); - this.postProcessGateway(builder, element, parserContext); + IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "encoding-mode"); + postProcessGateway(builder, element, parserContext); - IntegrationNamespaceUtils.configureHeaderMapper(element, builder, parserContext, DefaultSoapHeaderMapper.class, null); + IntegrationNamespaceUtils.configureHeaderMapper(element, builder, parserContext, + DefaultSoapHeaderMapper.class, null); return builder; } diff --git a/spring-integration-ws/src/main/java/org/springframework/integration/ws/dsl/BaseWsOutboundGatewaySpec.java b/spring-integration-ws/src/main/java/org/springframework/integration/ws/dsl/BaseWsOutboundGatewaySpec.java index 0f36d86436..7e89fd4e56 100644 --- a/spring-integration-ws/src/main/java/org/springframework/integration/ws/dsl/BaseWsOutboundGatewaySpec.java +++ b/spring-integration-ws/src/main/java/org/springframework/integration/ws/dsl/BaseWsOutboundGatewaySpec.java @@ -24,6 +24,7 @@ import org.springframework.integration.dsl.MessageHandlerSpec; import org.springframework.integration.util.JavaUtils; import org.springframework.integration.ws.AbstractWebServiceOutboundGateway; import org.springframework.integration.ws.SoapHeaderMapper; +import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.FaultMessageResolver; import org.springframework.ws.client.core.WebServiceMessageCallback; @@ -39,6 +40,8 @@ import org.springframework.ws.transport.WebServiceMessageSender; * @param the target {@link AbstractWebServiceOutboundGateway} implementation type. * * @author Gary Russell + * @author Artem Bilan + * * @since 5.3 * */ @@ -58,7 +61,7 @@ public abstract class BaseWsOutboundGatewaySpec< private SoapHeaderMapper headerMapper; - private boolean encodeUri = true; + private DefaultUriBuilderFactory.EncodingMode encodingMode; private boolean ignoreEmptyResponses = true; @@ -114,14 +117,12 @@ public abstract class BaseWsOutboundGatewaySpec< } /** - * Specify whether the URI should be encoded after any uriVariables - * are expanded and before sending the request. The default value is true. - * @param encodeUri true if the URI should be encoded. - * @return the spec. - * @see org.springframework.web.util.UriComponentsBuilder + * Specify a {@link DefaultUriBuilderFactory.EncodingMode} for uri construction. + * @param encodingMode to use for uri construction. + * @return the spec */ - public S encodeUri(boolean encodeUri) { - this.encodeUri = encodeUri; + public S encodingMode(DefaultUriBuilderFactory.EncodingMode encodingMode) { + this.encodingMode = encodingMode; return _this(); } @@ -158,7 +159,7 @@ public abstract class BaseWsOutboundGatewaySpec< gateway.setUriVariableExpressions(this.uriVariableExpressions); JavaUtils.INSTANCE .acceptIfNotNull(this.headerMapper, gateway::setHeaderMapper); - gateway.setEncodeUri(this.encodeUri); + gateway.setEncodingMode(this.encodingMode); gateway.setIgnoreEmptyResponses(this.ignoreEmptyResponses); gateway.setRequestCallback(this.requestCallback); return gateway; diff --git a/spring-integration-ws/src/main/resources/org/springframework/integration/ws/config/spring-integration-ws.xsd b/spring-integration-ws/src/main/resources/org/springframework/integration/ws/config/spring-integration-ws.xsd index ee2e44f749..76dc43e436 100644 --- a/spring-integration-ws/src/main/resources/org/springframework/integration/ws/config/spring-integration-ws.xsd +++ b/spring-integration-ws/src/main/resources/org/springframework/integration/ws/config/spring-integration-ws.xsd @@ -127,15 +127,26 @@ - When set to "false", the URI won't be encoded before the request is sent. This may be useful + [DEPRECATED] When set to "false", the URI won't be encoded before the request is sent. This may be useful in some scenarios as it allows user control over the encoding, if needed. Default is "true". This attribute is ignored, if 'destination-provider' is specified. + Deprecated since 5.3 in favor of 'encoding-mode'. + + + + Set the encoding mode during URI building. + + + + + + @@ -531,4 +542,13 @@ this list can also be simple patterns to be matched against the header names (e. + + + + + + + + + diff --git a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/UriVariableTests-context.xml b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/UriVariableTests-context.xml index 3fadc20858..e362ffc882 100644 --- a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/UriVariableTests-context.xml +++ b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/UriVariableTests-context.xml @@ -42,6 +42,7 @@ diff --git a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/UriVariableTests.java b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/UriVariableTests.java index ee918c9625..995229366a 100644 --- a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/UriVariableTests.java +++ b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/UriVariableTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,8 +37,7 @@ import javax.jms.Session; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.packet.Stanza; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -52,8 +51,7 @@ import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessageHandlingException; import org.springframework.messaging.MessagingException; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import org.springframework.ws.client.WebServiceClientException; import org.springframework.ws.client.WebServiceIOException; import org.springframework.ws.client.core.WebServiceMessageCallback; @@ -74,8 +72,7 @@ import org.springframework.ws.transport.mail.MailSenderConnection; * * @since 2.1 */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration +@SpringJUnitConfig public class UriVariableTests { @Autowired @@ -134,7 +131,7 @@ public class UriVariableTests { assertThatExceptionOfType(MessagingException.class) .isThrownBy(() -> this.inputHttp.send(message)) .withCauseInstanceOf(WebServiceIOException.class); // offline - assertThat(uri.get()).isEqualTo("http://localhost/spring-integration?param=test1%20&%20test2"); + assertThat(uri.get()).isEqualTo("http://localhost/spring-integration?param=test1%20%26%20test2"); } @Test diff --git a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests-context.xml b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests-context.xml index 8f4cf96900..4fa915c49f 100644 --- a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests-context.xml +++ b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests-context.xml @@ -127,7 +127,7 @@ diff --git a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java index 6bfec0764d..33e5b9b192 100644 --- a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java +++ b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.integration.ws.config; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -24,8 +25,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.springframework.beans.DirectFieldAccessor; @@ -49,7 +49,8 @@ import org.springframework.messaging.support.GenericMessage; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; import org.springframework.scheduling.support.PeriodicTrigger; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.FaultMessageResolver; import org.springframework.ws.client.core.SourceExtractor; @@ -66,7 +67,7 @@ import org.springframework.ws.transport.WebServiceMessageSender; * @author Gary Russell * @author Artem Bilan */ -@RunWith(SpringRunner.class) +@SpringJUnitConfig public class WebServiceOutboundGatewayParserTests { private static volatile int adviceCalled; @@ -173,7 +174,8 @@ public class WebServiceOutboundGatewayParserTests { @Test public void simpleGatewayWithCustomSourceExtractorAndMessageFactory() { - AbstractEndpoint endpoint = context.getBean("gatewayWithCustomSourceExtractorAndMessageFactory", AbstractEndpoint.class); + AbstractEndpoint endpoint = context.getBean("gatewayWithCustomSourceExtractorAndMessageFactory", + AbstractEndpoint.class); SourceExtractor sourceExtractor = (SourceExtractor) context.getBean("sourceExtractor"); assertThat(endpoint.getClass()).isEqualTo(EventDrivenConsumer.class); Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler"); @@ -187,7 +189,8 @@ public class WebServiceOutboundGatewayParserTests { @Test public void simpleGatewayWithCustomFaultMessageResolver() { - AbstractEndpoint endpoint = this.context.getBean("gatewayWithCustomFaultMessageResolver", AbstractEndpoint.class); + AbstractEndpoint endpoint = this.context.getBean("gatewayWithCustomFaultMessageResolver", + AbstractEndpoint.class); assertThat(endpoint.getClass()).isEqualTo(EventDrivenConsumer.class); Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler"); assertThat(gateway.getClass()).isEqualTo(SimpleWebServiceOutboundGateway.class); @@ -387,7 +390,7 @@ public class WebServiceOutboundGatewayParserTests { AbstractEndpoint endpoint = this.context.getBean("gatewayWithAdvice", AbstractEndpoint.class); assertThat(endpoint.getClass()).isEqualTo(EventDrivenConsumer.class); MessageHandler handler = TestUtils.getPropertyValue(endpoint, "handler", MessageHandler.class); - handler.handleMessage(new GenericMessage("foo")); + handler.handleMessage(new GenericMessage<>("foo")); assertThat(adviceCalled).isEqualTo(1); } @@ -395,18 +398,20 @@ public class WebServiceOutboundGatewayParserTests { public void testInt2718AdvisedInsideAChain() { adviceCalled = 0; MessageChannel channel = context.getBean("gatewayWithAdviceInsideAChain", MessageChannel.class); - channel.send(new GenericMessage("foo")); + channel.send(new GenericMessage<>("foo")); assertThat(adviceCalled).isEqualTo(1); } @Test - @SuppressWarnings("unchecked") public void jmsUri() { AbstractEndpoint endpoint = this.context.getBean("gatewayWithJmsUri", AbstractEndpoint.class); assertThat(endpoint.getClass()).isEqualTo(EventDrivenConsumer.class); MessageHandler handler = TestUtils.getPropertyValue(endpoint, "handler", MessageHandler.class); assertThat(TestUtils.getPropertyValue(handler, "destinationProvider")).isNull(); - assertThat(TestUtils.getPropertyValue(handler, "encodeUri", Boolean.class)).isFalse(); + assertThat( + TestUtils.getPropertyValue(handler, "uriFactory.encodingMode", + DefaultUriBuilderFactory.EncodingMode.class)) + .isEqualTo(DefaultUriBuilderFactory.EncodingMode.NONE); WebServiceTemplate webServiceTemplate = TestUtils.getPropertyValue(handler, "webServiceTemplate", WebServiceTemplate.class); @@ -418,23 +423,27 @@ public class WebServiceOutboundGatewayParserTests { new DirectFieldAccessor(handler).setPropertyValue("webServiceTemplate", webServiceTemplate); - handler.handleMessage(new GenericMessage("foo")); + handler.handleMessage(new GenericMessage<>("foo")); verify(webServiceTemplate).sendAndReceive(eq("jms:wsQueue"), any(WebServiceMessageCallback.class), ArgumentMatchers.>any()); } - @Test(expected = BeanDefinitionParsingException.class) + @Test public void invalidGatewayWithBothUriAndDestinationProvider() { - new ClassPathXmlApplicationContext("invalidGatewayWithBothUriAndDestinationProvider.xml", this.getClass()) - .close(); + assertThatExceptionOfType(BeanDefinitionParsingException.class) + .isThrownBy(() -> + new ClassPathXmlApplicationContext("invalidGatewayWithBothUriAndDestinationProvider.xml", + getClass())); } - @Test(expected = BeanDefinitionParsingException.class) + @Test public void invalidGatewayWithNeitherUriNorDestinationProvider() { - new ClassPathXmlApplicationContext("invalidGatewayWithNeitherUriNorDestinationProvider.xml", this.getClass()) - .close(); + assertThatExceptionOfType(BeanDefinitionParsingException.class) + .isThrownBy(() -> + new ClassPathXmlApplicationContext("invalidGatewayWithNeitherUriNorDestinationProvider.xml", + getClass())); } public static class FooAdvice extends AbstractRequestHandlerAdvice { diff --git a/spring-integration-ws/src/test/java/org/springframework/integration/ws/dsl/WsDslTests.java b/spring-integration-ws/src/test/java/org/springframework/integration/ws/dsl/WsDslTests.java index 9f329a5905..f98ad78bab 100644 --- a/spring-integration-ws/src/test/java/org/springframework/integration/ws/dsl/WsDslTests.java +++ b/spring-integration-ws/src/test/java/org/springframework/integration/ws/dsl/WsDslTests.java @@ -34,6 +34,7 @@ import org.springframework.integration.ws.SimpleWebServiceOutboundGateway; import org.springframework.integration.ws.SoapHeaderMapper; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; +import org.springframework.web.util.DefaultUriBuilderFactory; import org.springframework.ws.WebServiceMessageFactory; import org.springframework.ws.client.core.FaultMessageResolver; import org.springframework.ws.client.core.SourceExtractor; @@ -45,6 +46,8 @@ import org.springframework.ws.transport.WebServiceMessageSender; /** * @author Gary Russell + * @author Artem Bilan + * * @since 5.3 * */ @@ -93,7 +96,7 @@ public class WsDslTests { .marshaller(marshaller) .unmarshaller(unmarshaller) .messageFactory(messageFactory) - .encodeUri(true) + .encodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY) .faultMessageResolver(faultMessageResolver) .headerMapper(headerMapper) .ignoreEmptyResponses(true) @@ -111,7 +114,7 @@ public class WsDslTests { assertThat(TestUtils.getPropertyValue(gateway, "webServiceTemplate.interceptors", ClientInterceptor[].class)[0]) .isSameAs(interceptor); assertThat(TestUtils.getPropertyValue(gateway, "webServiceTemplate.messageSenders", - WebServiceMessageSender[].class)[0]) + WebServiceMessageSender[].class)[0]) .isSameAs(messageSender); assertThat(TestUtils.getPropertyValue(gateway, "requestCallback")).isSameAs(requestCallback); assertThat(TestUtils.getPropertyValue(gateway, "uriVariableExpressions")).isEqualTo(uriVariableExpressions); @@ -134,7 +137,7 @@ public class WsDslTests { .destinationProvider(destinationProvider) .sourceExtractor(sourceExtractor) .messageFactory(messageFactory) - .encodeUri(true) + .encodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY) .faultMessageResolver(faultMessageResolver) .headerMapper(headerMapper) .ignoreEmptyResponses(true) @@ -151,7 +154,7 @@ public class WsDslTests { assertThat(TestUtils.getPropertyValue(gateway, "webServiceTemplate.interceptors", ClientInterceptor[].class)[0]) .isSameAs(interceptor); assertThat(TestUtils.getPropertyValue(gateway, "webServiceTemplate.messageSenders", - WebServiceMessageSender[].class)[0]) + WebServiceMessageSender[].class)[0]) .isSameAs(messageSender); assertThat(TestUtils.getPropertyValue(gateway, "requestCallback")).isSameAs(requestCallback); assertThat(TestUtils.getPropertyValue(gateway, "uriVariableExpressions")).isEqualTo(uriVariableExpressions); @@ -169,7 +172,7 @@ public class WsDslTests { MarshallingWebServiceOutboundGateway gateway = Ws.marshallingOutboundGateway(template) .uri(uri) - .encodeUri(true) + .encodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY) .headerMapper(headerMapper) .ignoreEmptyResponses(true) .requestCallback(requestCallback) @@ -194,7 +197,7 @@ public class WsDslTests { Ws.simpleOutboundGateway(template) .uri(uri) .sourceExtractor(sourceExtractor) - .encodeUri(true) + .encodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY) .headerMapper(headerMapper) .ignoreEmptyResponses(true) .requestCallback(requestCallback) @@ -205,6 +208,10 @@ public class WsDslTests { assertThat(TestUtils.getPropertyValue(gateway, "requestCallback")).isSameAs(requestCallback); assertThat(TestUtils.getPropertyValue(gateway, "uriVariableExpressions")).isEqualTo(uriVariableExpressions); assertThat(TestUtils.getPropertyValue(gateway, "extractPayload", Boolean.class)).isFalse(); + assertThat( + TestUtils.getPropertyValue(gateway, "uriFactory.encodingMode", + DefaultUriBuilderFactory.EncodingMode.class)) + .isEqualTo(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY); } interface Both extends Marshaller, Unmarshaller { diff --git a/src/reference/asciidoc/http.adoc b/src/reference/asciidoc/http.adoc index 9afc6315ad..3c233588f5 100644 --- a/src/reference/asciidoc/http.adoc +++ b/src/reference/asciidoc/http.adoc @@ -715,7 +715,7 @@ If you wish to partially encode some of the URL, use an `expression` within a `< ==== [source,xml] ---- - + @@ -724,7 +724,7 @@ If you wish to partially encode some of the URL, use an `expression` within a `< ==== With Java DSL this option can be controlled by the `BaseHttpMessageHandlerSpec.encodingMode()` option. -Same configuration applies for similar outbound components in the <<./webflux.adoc/[webflux,WebFlux module>>. +The same configuration applies for similar outbound components in the <<./webflux.adoc#webflux,WebFlux module>> and <<./ws.adoc#ws,Web Services module>>. For much sophisticated scenarios it is recommended to configure an `UriTemplateHandler` on the externally provided `RestTemplate`; or in case of WebFlux - `WebClient` with it `UriBuilderFactory`. [[http-java-config]] diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index 311cd3ad32..721a0371a4 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -68,9 +68,11 @@ See <<./amqp.adoc#amqp-inbound-channel-adapter,AMQP Inbound Channel Adapter>> The `encodeUri` property on the `AbstractHttpRequestExecutingMessageHandler` has been deprecated in favor of newly introduced `encodingMode`. See `DefaultUriBuilderFactory.EncodingMode` JavaDocs and <<./http.adoc#http-uri-encoding,Controlling URI Encoding>> for more information. This also affects `WebFluxRequestExecutingMessageHandler`, respective Java DSL and XML configuration. +The same option is added into an `AbstractWebServiceOutboundGateway`. [[x5.3-ws]] === Web Services Changes Java DSL support has been added for Web Service components. +The `encodeUri` property on the `AbstractWebServiceOutboundGateway` has been deprecated in favor of newly introduced `encodingMode` - similar to HTTP changes above. See <<./ws.adoc#ws,Web Services Support>> for more information. diff --git a/src/reference/asciidoc/ws.adoc b/src/reference/asciidoc/ws.adoc index f5ee015774..b5e18db845 100644 --- a/src/reference/asciidoc/ws.adoc +++ b/src/reference/asciidoc/ws.adoc @@ -233,7 +233,7 @@ Examples: .handle(Ws.simpleOutboundGateway(template) .uri(uri) .sourceExtractor(sourceExtractor) - .encodeUri(true) + .encodingMode(DefaultUriBuilderFactory.EncodingMode.NONE) .headerMapper(headerMapper) .ignoreEmptyResponses(true) .requestCallback(requestCallback) @@ -251,7 +251,7 @@ Examples: .marshaller(marshaller) .unmarshaller(unmarshaller) .messageFactory(messageFactory) - .encodeUri(true) + .encodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY) .faultMessageResolver(faultMessageResolver) .headerMapper(headerMapper) .ignoreEmptyResponses(true) @@ -267,7 +267,7 @@ Examples: ---- .handle(Ws.marshallingOutboundGateway(template) .uri(uri) - .encodeUri(true) + .encodingMode(DefaultUriBuilderFactory.EncodingMode.URI_COMPONENT) .headerMapper(headerMapper) .ignoreEmptyResponses(true) .requestCallback(requestCallback) @@ -305,14 +305,14 @@ If you supply a `DestinationProvider`, variable substitution is not supported an By default, the URL string is encoded (see https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html[`UriComponentsBuilder`]) to the URI object before sending the request. In some scenarios with a non-standard URI, it is undesirable to perform the encoding. -Since version 4.1, the `` element provides an `encode-uri` attribute. -To disable encoding the URL, set this attribute `false` (it defaults to `true`). +The `` element provides an `encoding-mode` attribute. +To disable encoding the URL, set this attribute to `NONE` (by default, it is `TEMPLATE_AND_VALUES`). If you wish to partially encode some of the URL, you can do so by using an `expression` within a ``, as the following example shows: ==== [source,xml] ---- - + @@ -320,7 +320,7 @@ If you wish to partially encode some of the URL, you can do so by using an `expr ---- ==== -NOTE: If you set `DestinationProvider`, `encode-uri` is ignored. +NOTE: If you set `DestinationProvider`, `encoding-mode` is ignored. [[ws-message-headers]] === WS Message Headers