Skip to content

Commit faee3d3

Browse files
committed
GH-10574: Rely on WebServiceTemplate.defaultUri
Fixes: #10574 * Change the logic of the `AbstractWebServiceOutboundGateway` to take into account a `WebServiceTemplate.defaultUri` option as an alternative to the explicit `uri` or `destinationProvider` * Expose `WebServiceTemplate`-based ctor in the `SimpleWebServiceOutboundGateway` (The `MarshallingWebServiceOutboundGateway` already has one) * Adjust tests and XML parser to cover a new logic * Mention the change in docs
1 parent 39e4659 commit faee3d3

File tree

9 files changed

+74
-32
lines changed

9 files changed

+74
-32
lines changed

spring-integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
5858
String uri = element.getAttribute("uri");
5959
String destinationProvider = element.getAttribute("destination-provider");
6060
List<Element> uriVariableElements = DomUtils.getChildElementsByTagName(element, "uri-variable");
61-
if (StringUtils.hasText(destinationProvider) == StringUtils.hasText(uri)) {
61+
if (StringUtils.hasText(destinationProvider) && StringUtils.hasText(uri)) {
6262
parserContext.getReaderContext().error(
6363
"Exactly one of 'uri' or 'destination-provider' is required.", element);
6464
}
@@ -140,7 +140,9 @@ protected void postProcessGateway(BeanDefinitionBuilder builder, Element element
140140
}
141141
}
142142

143-
private void parseMarshallerAttribute(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
143+
private static void parseMarshallerAttribute(BeanDefinitionBuilder builder, Element element,
144+
ParserContext parserContext) {
145+
144146
String marshallerRef = element.getAttribute("marshaller");
145147
String unmarshallerRef = element.getAttribute("unmarshaller");
146148
if (StringUtils.hasText(marshallerRef)) {

spring-integration-ws/src/main/java/org/springframework/integration/ws/outbound/AbstractWebServiceOutboundGateway.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,14 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
6969

7070
private final Lock lock = new ReentrantLock();
7171

72-
protected final DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory(); // NOSONAR - final
73-
74-
private final @Nullable String uri;
72+
protected final DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory();
7573

7674
private final @Nullable DestinationProvider destinationProvider;
7775

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

78+
private @Nullable String uri;
79+
8080
@SuppressWarnings("NullAway.Init")
8181
private StandardEvaluationContext evaluationContext;
8282

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

9191
private boolean webServiceTemplateExplicitlySet;
9292

93-
public AbstractWebServiceOutboundGateway(@Nullable final String uri, @Nullable WebServiceMessageFactory messageFactory) {
94-
Assert.hasText(uri, "URI must not be empty");
93+
public AbstractWebServiceOutboundGateway(@Nullable final String uri,
94+
@Nullable WebServiceMessageFactory messageFactory) {
95+
9596
this.webServiceTemplate = messageFactory != null ?
9697
new WebServiceTemplate(messageFactory) : new WebServiceTemplate();
9798
this.destinationProvider = null;
@@ -106,11 +107,16 @@ public AbstractWebServiceOutboundGateway(DestinationProvider destinationProvider
106107
new WebServiceTemplate(messageFactory) : new WebServiceTemplate();
107108
this.destinationProvider = destinationProvider;
108109
// we always call WebServiceTemplate methods with an explicit URI argument,
109-
// but in case the WebServiceTemplate is accessed directly we'll set this:
110+
// but in case the WebServiceTemplate is accessed directly, we'll set this:
110111
this.webServiceTemplate.setDestinationProvider(destinationProvider);
111112
this.uri = null;
112113
}
113114

115+
public AbstractWebServiceOutboundGateway(WebServiceTemplate webServiceTemplate) {
116+
doSetWebServiceTemplate(webServiceTemplate);
117+
this.destinationProvider = null;
118+
}
119+
114120
public void setHeaderMapper(SoapHeaderMapper headerMapper) {
115121
Assert.notNull(headerMapper, "'headerMapper' must not be null");
116122
this.headerMapper = headerMapper;
@@ -165,6 +171,9 @@ protected final void doSetWebServiceTemplate(WebServiceTemplate template) {
165171
Assert.notNull(template, "'webServiceTemplate' must not be null");
166172
this.webServiceTemplate = template;
167173
this.webServiceTemplateExplicitlySet = true;
174+
if (!StringUtils.hasText(this.uri)) {
175+
this.uri = this.webServiceTemplate.getDefaultUri();
176+
}
168177
}
169178

170179
public void setMessageFactory(WebServiceMessageFactory messageFactory) {
@@ -200,6 +209,10 @@ protected void doInit() {
200209
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
201210
Assert.state(this.destinationProvider == null || CollectionUtils.isEmpty(this.uriVariableExpressions),
202211
"uri variables are not supported when a DestinationProvider is supplied.");
212+
213+
Assert.state(this.destinationProvider != null || StringUtils.hasText(this.uri),
214+
"'destinationProvider' or 'uri' must be provided, " +
215+
"or 'defaultUri' must be set on the 'WebServiceTemplate'");
203216
}
204217

205218
protected WebServiceTemplate getWebServiceTemplate() {
@@ -234,7 +247,7 @@ protected WebServiceTemplate getWebServiceTemplate() {
234247
.withRoot(requestMessage)
235248
.build();
236249

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

spring-integration-ws/src/main/java/org/springframework/integration/ws/outbound/SimpleWebServiceOutboundGateway.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.springframework.ws.WebServiceMessageFactory;
3636
import org.springframework.ws.client.core.SourceExtractor;
3737
import org.springframework.ws.client.core.WebServiceMessageCallback;
38+
import org.springframework.ws.client.core.WebServiceTemplate;
3839
import org.springframework.ws.client.support.destination.DestinationProvider;
3940
import org.springframework.ws.mime.Attachment;
4041
import org.springframework.ws.mime.MimeMessage;
@@ -91,6 +92,28 @@ public SimpleWebServiceOutboundGateway(@Nullable String uri, @Nullable SourceExt
9192
this.sourceExtractor = (sourceExtractor != null) ? sourceExtractor : new DefaultSourceExtractor();
9293
}
9394

95+
/**
96+
* Create an instance based on the predefined {@link WebServiceTemplate}
97+
* as an alternative to fine-grained configuration.
98+
* @param template the {@link WebServiceTemplate} to use.
99+
* @since 7.1
100+
*/
101+
public SimpleWebServiceOutboundGateway(WebServiceTemplate template) {
102+
this(template, null);
103+
}
104+
105+
/**
106+
* Create an instance based on the predefined {@link WebServiceTemplate}
107+
* as an alternative to fine-grained configuration.
108+
* @param template the {@link WebServiceTemplate} to use.
109+
* @param sourceExtractor the {@link SourceExtractor} to use.
110+
* @since 7.1
111+
*/
112+
public SimpleWebServiceOutboundGateway(WebServiceTemplate template, @Nullable SourceExtractor<?> sourceExtractor) {
113+
super(template);
114+
this.sourceExtractor = (sourceExtractor != null) ? sourceExtractor : new DefaultSourceExtractor();
115+
}
116+
94117
/**
95118
* A flag to return the whole {@link WebServiceMessage} or build
96119
* {@code payload} based on {@link WebServiceMessage}

spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests-context.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@
2323
<si:queue capacity="10"/>
2424
</si:channel>
2525

26-
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"/>
26+
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
27+
<property name="defaultUri" value="https://example.org" />
28+
</bean>
2729

2830
<ws:outbound-gateway id="gatewayWithReplyChannel"
2931
request-channel="inputChannel"
30-
uri="https://example.org"
3132
reply-channel="outputChannel"
3233
reply-timeout="777"
3334
web-service-template="webServiceTemplate"

spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.mockito.ArgumentMatchers;
2323

2424
import org.springframework.beans.DirectFieldAccessor;
25+
import org.springframework.beans.factory.BeanCreationException;
2526
import org.springframework.beans.factory.annotation.Autowired;
2627
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
2728
import org.springframework.context.ApplicationContext;
@@ -444,10 +445,12 @@ public void invalidGatewayWithBothUriAndDestinationProvider() {
444445

445446
@Test
446447
public void invalidGatewayWithNeitherUriNorDestinationProvider() {
447-
assertThatExceptionOfType(BeanDefinitionParsingException.class)
448+
assertThatExceptionOfType(BeanCreationException.class)
448449
.isThrownBy(() ->
449450
new ClassPathXmlApplicationContext("invalidGatewayWithNeitherUriNorDestinationProvider.xml",
450-
getClass()));
451+
getClass()))
452+
.withMessageContaining("'destinationProvider' or 'uri' must be provided, " +
453+
"or 'defaultUri' must be set on the 'WebServiceTemplate'");
451454
}
452455

453456
public static class FooAdvice extends AbstractRequestHandlerAdvice {
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,21 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<beans xmlns="http://www.springframework.org/schema/beans"
3-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4-
xmlns:si="http://www.springframework.org/schema/integration"
5-
xmlns:ws="http://www.springframework.org/schema/integration/ws"
6-
xmlns:util='http://www.springframework.org/schema/util'
7-
xsi:schemaLocation="http://www.springframework.org/schema/beans
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:si="http://www.springframework.org/schema/integration"
5+
xmlns:ws="http://www.springframework.org/schema/integration/ws"
6+
xsi:schemaLocation="http://www.springframework.org/schema/beans
87
https://www.springframework.org/schema/beans/spring-beans.xsd
98
http://www.springframework.org/schema/integration
109
https://www.springframework.org/schema/integration/spring-integration.xsd
1110
http://www.springframework.org/schema/integration/ws
12-
https://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd
13-
http://www.springframework.org/schema/util
14-
https://www.springframework.org/schema/util/spring-util.xsd">
11+
https://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd">
1512

1613
<si:channel id="inputChannel"/>
1714

1815
<si:channel id="outputChannel">
1916
<si:queue capacity="10"/>
2017
</si:channel>
2118

22-
<ws:outbound-gateway id="gatewayWithBothUriAndDestinationProvider"
23-
request-channel="inputChannel"/>
24-
25-
<bean id="destinationProvider" class="org.springframework.integration.ws.config.StubDestinationProvider"/>
19+
<ws:outbound-gateway id="gatewayWithoutNeitherUriNorDestinationProvider" request-channel="inputChannel"/>
2620

2721
</beans>

spring-integration-ws/src/test/java/org/springframework/integration/ws/dsl/WsDslTests.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,10 @@ void marshallingOutboundTemplate() {
175175
WebServiceMessageCallback requestCallback = msg -> {
176176
};
177177
Map<String, Expression> uriVariableExpressions = new HashMap<>();
178-
uriVariableExpressions.put("foo", new LiteralExpression("bar"));
179-
WebServiceTemplate template = mock();
180-
String uri = "foo";
178+
uriVariableExpressions.put("testVariable", new LiteralExpression("testValue"));
179+
WebServiceTemplate template = new WebServiceTemplate();
180+
String uri = "testUri";
181+
template.setDefaultUri(uri);
181182
MarshallingWebServiceOutboundGateway gateway =
182183
Ws.marshallingOutboundGateway(template)
183184
.uri(uri)
@@ -202,13 +203,12 @@ void simpleOutboundTemplate() {
202203
WebServiceMessageCallback requestCallback = msg -> {
203204
};
204205
Map<String, Expression> uriVariableExpressions = new HashMap<>();
205-
uriVariableExpressions.put("foo", new LiteralExpression("bar"));
206+
uriVariableExpressions.put("testVariable", new LiteralExpression("testValue"));
206207
SourceExtractor<?> sourceExtractor = mock();
207-
WebServiceTemplate template = mock();
208-
String uri = "foo";
208+
WebServiceTemplate template = new WebServiceTemplate();
209+
template.setDefaultUri("testUri");
209210
SimpleWebServiceOutboundGateway gateway =
210211
Ws.simpleOutboundGateway(template)
211-
.uri(uri)
212212
.sourceExtractor(sourceExtractor)
213213
.encodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY)
214214
.headerMapper(headerMapper)

src/reference/antora/modules/ROOT/pages/whats-new.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ For more details, see the https://github.com/spring-projects/spring-integration/
1414
In general, the project has been moved to the latest dependency versions.
1515
Java 17 is still the baseline, but Java 25 is supported.
1616

17+
[[x7.0-web-services-changes]]
18+
=== Web Services Support Changes
19+
20+
The Web Services Outbound Gateway now can rely on the provided `WebServiceTemplate.defaultUri`.
21+
See xref:ws.adoc[] for more information.

src/reference/antora/modules/ROOT/pages/ws.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ To invoke a web service when you send a message to a channel, you have two optio
4040
The former accepts either a `String` or `javax.xml.transform.Source` as the message payload.
4141
The latter supports any implementation of the `Marshaller` and `Unmarshaller` interfaces.
4242
Both require a Spring Web Services `DestinationProvider`, to determine the URI of the web service to be called.
43+
Or explicit uri directly, or via `WebServiceTemplate.defaultUri` (since version 7.1).
4344
The following example shows both options for invoking a web service:
4445

4546
[source,java]

0 commit comments

Comments
 (0)