Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
String uri = element.getAttribute("uri");
String destinationProvider = element.getAttribute("destination-provider");
List<Element> uriVariableElements = DomUtils.getChildElementsByTagName(element, "uri-variable");
if (StringUtils.hasText(destinationProvider) == StringUtils.hasText(uri)) {
if (StringUtils.hasText(destinationProvider) && StringUtils.hasText(uri)) {
parserContext.getReaderContext().error(
"Exactly one of 'uri' or 'destination-provider' is required.", element);
}
Expand Down Expand Up @@ -140,7 +140,9 @@ protected void postProcessGateway(BeanDefinitionBuilder builder, Element element
}
}

private void parseMarshallerAttribute(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
private static void parseMarshallerAttribute(BeanDefinitionBuilder builder, Element element,
ParserContext parserContext) {

String marshallerRef = element.getAttribute("marshaller");
String unmarshallerRef = element.getAttribute("unmarshaller");
if (StringUtils.hasText(marshallerRef)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro

private final Lock lock = new ReentrantLock();

protected final DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory(); // NOSONAR - final

private final @Nullable String uri;
protected final DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory();

private final @Nullable DestinationProvider destinationProvider;

private final Map<String, Expression> uriVariableExpressions = new HashMap<>();

private @Nullable String uri;

@SuppressWarnings("NullAway.Init")
private StandardEvaluationContext evaluationContext;

Expand All @@ -90,8 +90,9 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro

private boolean webServiceTemplateExplicitlySet;

public AbstractWebServiceOutboundGateway(@Nullable final String uri, @Nullable WebServiceMessageFactory messageFactory) {
Assert.hasText(uri, "URI must not be empty");
public AbstractWebServiceOutboundGateway(@Nullable final String uri,
@Nullable WebServiceMessageFactory messageFactory) {

this.webServiceTemplate = messageFactory != null ?
new WebServiceTemplate(messageFactory) : new WebServiceTemplate();
this.destinationProvider = null;
Expand All @@ -106,11 +107,16 @@ public AbstractWebServiceOutboundGateway(DestinationProvider destinationProvider
new WebServiceTemplate(messageFactory) : new WebServiceTemplate();
this.destinationProvider = destinationProvider;
// we always call WebServiceTemplate methods with an explicit URI argument,
// but in case the WebServiceTemplate is accessed directly we'll set this:
// but in case the WebServiceTemplate is accessed directly, we'll set this:
this.webServiceTemplate.setDestinationProvider(destinationProvider);
this.uri = null;
}

public AbstractWebServiceOutboundGateway(WebServiceTemplate webServiceTemplate) {
doSetWebServiceTemplate(webServiceTemplate);
this.destinationProvider = null;
}

public void setHeaderMapper(SoapHeaderMapper headerMapper) {
Assert.notNull(headerMapper, "'headerMapper' must not be null");
this.headerMapper = headerMapper;
Expand Down Expand Up @@ -165,6 +171,9 @@ protected final void doSetWebServiceTemplate(WebServiceTemplate template) {
Assert.notNull(template, "'webServiceTemplate' must not be null");
this.webServiceTemplate = template;
this.webServiceTemplateExplicitlySet = true;
if (!StringUtils.hasText(this.uri)) {
this.uri = this.webServiceTemplate.getDefaultUri();
}
}

public void setMessageFactory(WebServiceMessageFactory messageFactory) {
Expand Down Expand Up @@ -200,6 +209,10 @@ protected void doInit() {
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
Assert.state(this.destinationProvider == null || CollectionUtils.isEmpty(this.uriVariableExpressions),
"uri variables are not supported when a DestinationProvider is supplied.");

Assert.state(this.destinationProvider != null || StringUtils.hasText(this.uri),
"'destinationProvider' or 'uri' must be provided, " +
"or 'defaultUri' must be set on the 'WebServiceTemplate'");
}

protected WebServiceTemplate getWebServiceTemplate() {
Expand Down Expand Up @@ -234,7 +247,7 @@ protected WebServiceTemplate getWebServiceTemplate() {
.withRoot(requestMessage)
.build();

Assert.notNull(this.uri, "'uri' must not be null");
Assert.hasText(this.uri, "'uri' must be provided, or 'defaultUri' must be set on the 'WebServiceTemplate'");
return this.uriFactory.expand(this.uri, uriVariables);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.SourceExtractor;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.client.support.destination.DestinationProvider;
import org.springframework.ws.mime.Attachment;
import org.springframework.ws.mime.MimeMessage;
Expand Down Expand Up @@ -91,6 +92,28 @@ public SimpleWebServiceOutboundGateway(@Nullable String uri, @Nullable SourceExt
this.sourceExtractor = (sourceExtractor != null) ? sourceExtractor : new DefaultSourceExtractor();
}

/**
* Create an instance based on the predefined {@link WebServiceTemplate}
* as an alternative to fine-grained configuration.
* @param template the {@link WebServiceTemplate} to use.
* @since 7.1
*/
public SimpleWebServiceOutboundGateway(WebServiceTemplate template) {
this(template, null);
}

/**
* Create an instance based on the predefined {@link WebServiceTemplate}
* as an alternative to fine-grained configuration.
* @param template the {@link WebServiceTemplate} to use.
* @param sourceExtractor the {@link SourceExtractor} to use.
* @since 7.1
*/
public SimpleWebServiceOutboundGateway(WebServiceTemplate template, @Nullable SourceExtractor<?> sourceExtractor) {
super(template);
this.sourceExtractor = (sourceExtractor != null) ? sourceExtractor : new DefaultSourceExtractor();
}

/**
* A flag to return the whole {@link WebServiceMessage} or build
* {@code payload} based on {@link WebServiceMessage}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
<si:queue capacity="10"/>
</si:channel>

<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"/>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="defaultUri" value="https://example.org" />
</bean>

<ws:outbound-gateway id="gatewayWithReplyChannel"
request-channel="inputChannel"
uri="https://example.org"
reply-channel="outputChannel"
reply-timeout="777"
web-service-template="webServiceTemplate"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.mockito.ArgumentMatchers;

import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.ApplicationContext;
Expand Down Expand Up @@ -444,10 +445,12 @@ public void invalidGatewayWithBothUriAndDestinationProvider() {

@Test
public void invalidGatewayWithNeitherUriNorDestinationProvider() {
assertThatExceptionOfType(BeanDefinitionParsingException.class)
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() ->
new ClassPathXmlApplicationContext("invalidGatewayWithNeitherUriNorDestinationProvider.xml",
getClass()));
getClass()))
.withMessageContaining("'destinationProvider' or 'uri' must be provided, " +
"or 'defaultUri' must be set on the 'WebServiceTemplate'");
}

public static class FooAdvice extends AbstractRequestHandlerAdvice {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:si="http://www.springframework.org/schema/integration"
xmlns:ws="http://www.springframework.org/schema/integration/ws"
xmlns:util='http://www.springframework.org/schema/util'
xsi:schemaLocation="http://www.springframework.org/schema/beans
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:si="http://www.springframework.org/schema/integration"
xmlns:ws="http://www.springframework.org/schema/integration/ws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ws
https://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd
http://www.springframework.org/schema/util
https://www.springframework.org/schema/util/spring-util.xsd">
https://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd">

<si:channel id="inputChannel"/>

<si:channel id="outputChannel">
<si:queue capacity="10"/>
</si:channel>

<ws:outbound-gateway id="gatewayWithBothUriAndDestinationProvider"
request-channel="inputChannel"/>

<bean id="destinationProvider" class="org.springframework.integration.ws.config.StubDestinationProvider"/>
<ws:outbound-gateway id="gatewayWithoutNeitherUriNorDestinationProvider" request-channel="inputChannel"/>

</beans>
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,10 @@ void marshallingOutboundTemplate() {
WebServiceMessageCallback requestCallback = msg -> {
};
Map<String, Expression> uriVariableExpressions = new HashMap<>();
uriVariableExpressions.put("foo", new LiteralExpression("bar"));
WebServiceTemplate template = mock();
String uri = "foo";
uriVariableExpressions.put("testVariable", new LiteralExpression("testValue"));
WebServiceTemplate template = new WebServiceTemplate();
String uri = "testUri";
template.setDefaultUri(uri);
MarshallingWebServiceOutboundGateway gateway =
Ws.marshallingOutboundGateway(template)
.uri(uri)
Expand All @@ -202,13 +203,12 @@ void simpleOutboundTemplate() {
WebServiceMessageCallback requestCallback = msg -> {
};
Map<String, Expression> uriVariableExpressions = new HashMap<>();
uriVariableExpressions.put("foo", new LiteralExpression("bar"));
uriVariableExpressions.put("testVariable", new LiteralExpression("testValue"));
SourceExtractor<?> sourceExtractor = mock();
WebServiceTemplate template = mock();
String uri = "foo";
WebServiceTemplate template = new WebServiceTemplate();
template.setDefaultUri("testUri");
SimpleWebServiceOutboundGateway gateway =
Ws.simpleOutboundGateway(template)
.uri(uri)
.sourceExtractor(sourceExtractor)
.encodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY)
.headerMapper(headerMapper)
Expand Down
5 changes: 5 additions & 0 deletions src/reference/antora/modules/ROOT/pages/whats-new.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ For more details, see the https://github.com/spring-projects/spring-integration/
In general, the project has been moved to the latest dependency versions.
Java 17 is still the baseline, but Java 25 is supported.

[[x7.0-web-services-changes]]
=== Web Services Support Changes

The Web Services Outbound Gateway now can rely on the provided `WebServiceTemplate.defaultUri`.
See xref:ws.adoc[] for more information.
1 change: 1 addition & 0 deletions src/reference/antora/modules/ROOT/pages/ws.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ To invoke a web service when you send a message to a channel, you have two optio
The former accepts either a `String` or `javax.xml.transform.Source` as the message payload.
The latter supports any implementation of the `Marshaller` and `Unmarshaller` interfaces.
Both require a Spring Web Services `DestinationProvider`, to determine the URI of the web service to be called.
Or explicit uri directly, or via `WebServiceTemplate.defaultUri` (since version 7.1).
The following example shows both options for invoking a web service:

[source,java]
Expand Down