This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 1ec55622dbb4 CAMEL-26142: camel-spring-ws - null reply body, non-XML
reply body, and File/InputStream producer bodies (#28915)
1ec55622dbb4 is described below
commit 1ec55622dbb482a6bdd1ccbf7f011f36ba7232fe
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Nov 2 20:44:03 2026 +0100
CAMEL-26142: camel-spring-ws - null reply body, non-XML reply body, and
File/InputStream producer bodies (#28915)
* CAMEL-26142: camel-spring-ws - null reply body, non-XML reply body, a…
…nd File/InputStream producer bodies
A consumer route that set the body to null in a processor replied with the
request
payload, as SpringWebserviceMessage created the body again from the
request. The body
is now only created from the request until it has been set.
A consumer reply body that did not convert to Source gave an empty SOAP
body; it now
gives a SOAP fault with the conversion error. The producer and the consumer
now send a
File or a raw InputStream body as a StreamSource, as no type converter
covers these.
* CAMEL-26142: camel-spring-ws - file consumer bodies, and an OUT messa…
…ge without the request payload
The producer failed for the GenericFile body of a file consumer, as there
is no File to
Source converter; it now uses the content of a WrappedFile. A new message
from
SpringWebserviceMessage.newInstance(), such as the OUT message of
exchange.getOut(),
no longer creates its body from the request payload.
* CAMEL-26142: camel-spring-ws - end the test Spring XML files with a n…
…ewline
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../camel/catalog/docs/spring-ws-component.adoc | 8 ++
.../src/main/docs/spring-ws-component.adoc | 8 ++
.../spring/ws/SpringWebserviceConsumer.java | 4 +-
.../spring/ws/SpringWebserviceHelper.java | 27 ++++
.../spring/ws/SpringWebserviceMessage.java | 24 +++-
.../spring/ws/SpringWebserviceProducer.java | 3 +-
.../component/spring/ws/ConsumerReplyBodyTest.java | 137 +++++++++++++++++++++
.../spring/ws/ProducerLocalRouteTest.java | 45 +++++++
.../spring/ws/ConsumerReplyBodyTest-context.xml | 29 +++++
.../spring/ws/ProducerLocalRouteTest-context.xml | 13 +-
.../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 13 ++
11 files changed, 306 insertions(+), 5 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spring-ws-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spring-ws-component.adoc
index 8a54d2036e31..22eae0bb9d7f 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spring-ws-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/spring-ws-component.adoc
@@ -134,6 +134,10 @@ template.requestBody("direct:example", "<foobar
xmlns=\"http://foo.com\"><msg>te
Remember if it's a SOAP service you're calling, you don't have to include
SOAP tags. Spring-WS will perform the XML-to-SOAP marshaling.
+The body is sent as the payload of the request. It can be anything that
converts to a `javax.xml.transform.Source`,
+such as XML in a `String` or `byte[]`, a DOM `Document`, a `File` (also from
the `file` or `ftp` consumers) or an
+`InputStream`.
+
=== Sending SOAP and WS-Addressing action headers
When a remote web service requires a SOAP action or use of the
@@ -461,6 +465,10 @@ comes in). Also remember to check out the
Spring Web Services Example included in the
Camel distribution.
+The body of the message at the end of the route is the payload of the reply,
and it is converted to a
+`javax.xml.transform.Source` as for the producer. A `null` body gives an empty
SOAP body. A body that does not convert,
+such as a `Map`, gives a SOAP fault with the conversion error.
+
=== Endpoint mapping in routes
With the XML configuration in place, you can now use Camel's DSL to
diff --git
a/components/camel-spring-parent/camel-spring-ws/src/main/docs/spring-ws-component.adoc
b/components/camel-spring-parent/camel-spring-ws/src/main/docs/spring-ws-component.adoc
index 8a54d2036e31..22eae0bb9d7f 100644
---
a/components/camel-spring-parent/camel-spring-ws/src/main/docs/spring-ws-component.adoc
+++
b/components/camel-spring-parent/camel-spring-ws/src/main/docs/spring-ws-component.adoc
@@ -134,6 +134,10 @@ template.requestBody("direct:example", "<foobar
xmlns=\"http://foo.com\"><msg>te
Remember if it's a SOAP service you're calling, you don't have to include
SOAP tags. Spring-WS will perform the XML-to-SOAP marshaling.
+The body is sent as the payload of the request. It can be anything that
converts to a `javax.xml.transform.Source`,
+such as XML in a `String` or `byte[]`, a DOM `Document`, a `File` (also from
the `file` or `ftp` consumers) or an
+`InputStream`.
+
=== Sending SOAP and WS-Addressing action headers
When a remote web service requires a SOAP action or use of the
@@ -461,6 +465,10 @@ comes in). Also remember to check out the
Spring Web Services Example included in the
Camel distribution.
+The body of the message at the end of the route is the payload of the reply,
and it is converted to a
+`javax.xml.transform.Source` as for the producer. A `null` body gives an empty
SOAP body. A body that does not convert,
+such as a `Map`, gives a SOAP fault with the conversion error.
+
=== Endpoint mapping in routes
With the XML configuration in place, you can now use Camel's DSL to
diff --git
a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceConsumer.java
b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceConsumer.java
index fe99670941d9..97a0c64d0347 100644
---
a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceConsumer.java
+++
b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceConsumer.java
@@ -44,6 +44,7 @@ import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import static
org.apache.camel.component.spring.ws.SpringWebserviceHelper.toResult;
+import static
org.apache.camel.component.spring.ws.SpringWebserviceHelper.toSource;
public class SpringWebserviceConsumer extends DefaultConsumer implements
MessageEndpoint {
@@ -83,7 +84,8 @@ public class SpringWebserviceConsumer extends DefaultConsumer
implements Message
} else if (exchange.getPattern().isOutCapable()) {
Message responseMessage = exchange.getMessage(Message.class);
if (responseMessage != null) {
- Source responseBody =
responseMessage.getBody(Source.class);
+ // a null body gives an empty SOAP body, a body that is
not XML fails with a fault
+ Source responseBody = responseMessage.getBody() != null ?
toSource(responseMessage) : null;
WebServiceMessage response = messageContext.getResponse();
configuration.getMessageFilter().filterConsumer(exchange,
response);
toResult(responseBody, response.getPayloadResult());
diff --git
a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceHelper.java
b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceHelper.java
index 394a1cb51cef..49f51176812f 100644
---
a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceHelper.java
+++
b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceHelper.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.component.spring.ws;
+import java.io.File;
+import java.io.InputStream;
import java.util.Properties;
import javax.xml.transform.Result;
@@ -23,7 +25,12 @@ import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamSource;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.Message;
+import org.apache.camel.StreamCache;
+import org.apache.camel.WrappedFile;
import org.apache.camel.support.builder.xml.XMLConverterHelper;
import org.apache.camel.util.ObjectHelper;
@@ -34,6 +41,26 @@ public final class SpringWebserviceHelper {
private SpringWebserviceHelper() {
}
+ /**
+ * Returns the message body as a {@link Source}. A {@link File} or an
{@link InputStream} (that is not stream
+ * cached) is wrapped in a {@link StreamSource}, as there is no type
converter from these to {@link Source}. For a
+ * {@link WrappedFile} (such as from the file or ftp consumers) its
content is used.
+ *
+ * @throws InvalidPayloadException if the body cannot be converted to
{@link Source}
+ */
+ public static Source toSource(Message message) throws
InvalidPayloadException {
+ Object body = message.getBody();
+ if (body instanceof WrappedFile<?> wrappedFile) {
+ body = wrappedFile.getBody();
+ }
+ if (body instanceof File file) {
+ return new StreamSource(file);
+ } else if (body instanceof InputStream is && !(body instanceof
StreamCache)) {
+ return new StreamSource(is);
+ }
+ return message.getMandatoryBody(Source.class);
+ }
+
public static void toResult(Source source, Result result) throws
TransformerException {
if (source != null) {
XMLConverterHelper xml = new XMLConverterHelper();
diff --git
a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceMessage.java
b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceMessage.java
index 49274a423268..854cda4fe8c6 100644
---
a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceMessage.java
+++
b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceMessage.java
@@ -17,11 +17,14 @@
package org.apache.camel.component.spring.ws;
import org.apache.camel.CamelContext;
+import org.apache.camel.spi.DataType;
import org.apache.camel.support.DefaultMessage;
import org.springframework.ws.WebServiceMessage;
public class SpringWebserviceMessage extends DefaultMessage {
private WebServiceMessage webServiceMessage;
+ // the body is created from the web service payload only until the body
has been set (also to null)
+ private boolean bodySet;
public SpringWebserviceMessage(CamelContext camelContext,
WebServiceMessage webServiceMessage) {
super(camelContext);
@@ -32,11 +35,24 @@ public class SpringWebserviceMessage extends DefaultMessage
{
public void reset() {
super.reset();
webServiceMessage = null;
+ bodySet = false;
+ }
+
+ @Override
+ public void setBody(Object body) {
+ super.setBody(body);
+ bodySet = true;
+ }
+
+ @Override
+ public void setBody(Object body, DataType type) {
+ super.setBody(body, type);
+ bodySet = true;
}
@Override
protected Object createBody() {
- if (webServiceMessage != null) {
+ if (webServiceMessage != null && !bodySet) {
return webServiceMessage.getPayloadSource();
}
return null;
@@ -48,11 +64,15 @@ public class SpringWebserviceMessage extends DefaultMessage
{
public void setWebServiceMessage(WebServiceMessage webServiceMessage) {
this.webServiceMessage = webServiceMessage;
+ this.bodySet = false;
}
@Override
public DefaultMessage newInstance() {
- return new SpringWebserviceMessage(getCamelContext(),
webServiceMessage);
+ SpringWebserviceMessage answer = new
SpringWebserviceMessage(getCamelContext(), webServiceMessage);
+ // a new message (such as the OUT message) starts without a body, and
does not take the request payload
+ answer.bodySet = true;
+ return answer;
}
@Override
diff --git
a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceProducer.java
b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceProducer.java
index f31558346062..6db5de51fe36 100644
---
a/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceProducer.java
+++
b/components/camel-spring-parent/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceProducer.java
@@ -59,6 +59,7 @@ import
org.springframework.ws.transport.http.HttpUrlConnection;
import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender;
import static
org.apache.camel.component.spring.ws.SpringWebserviceHelper.toResult;
+import static
org.apache.camel.component.spring.ws.SpringWebserviceHelper.toSource;
public class SpringWebserviceProducer extends DefaultProducer {
@@ -77,7 +78,7 @@ public class SpringWebserviceProducer extends DefaultProducer
{
@Override
public void process(Exchange exchange) throws Exception {
// Let Camel TypeConverter hierarchy handle the conversion of XML
messages to Source objects
- Source sourcePayload = exchange.getIn().getMandatoryBody(Source.class);
+ Source sourcePayload = toSource(exchange.getIn());
// Extract optional headers
String endpointUriHeader =
exchange.getIn().getHeader(SpringWebserviceConstants.SPRING_WS_ENDPOINT_URI,
String.class);
diff --git
a/components/camel-spring-parent/camel-spring-ws/src/test/java/org/apache/camel/component/spring/ws/ConsumerReplyBodyTest.java
b/components/camel-spring-parent/camel-spring-ws/src/test/java/org/apache/camel/component/spring/ws/ConsumerReplyBodyTest.java
new file mode 100644
index 000000000000..dfe01296f0e4
--- /dev/null
+++
b/components/camel-spring-parent/camel-spring-ws/src/test/java/org/apache/camel/component/spring/ws/ConsumerReplyBodyTest.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.camel.component.spring.ws;
+
+import java.io.ByteArrayInputStream;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.spring.ws.bean.CamelEndpointMapping;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.apache.camel.test.spring.junit6.CamelSpringTest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.ws.test.server.MockWebServiceClient;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.springframework.ws.test.server.RequestCreators.withPayload;
+import static org.springframework.ws.test.server.ResponseMatchers.noFault;
+import static org.springframework.ws.test.server.ResponseMatchers.payload;
+import static
org.springframework.ws.test.server.ResponseMatchers.serverOrReceiverFault;
+
+/**
+ * The reply of a spring-ws consumer route: a null body, a body that is not
XML and an InputStream body.
+ */
+@ContextConfiguration
+@CamelSpringTest
+public class ConsumerReplyBodyTest extends CamelTestSupport {
+
+ private static final String REPLY = "<Reply
xmlns=\"http://www.webserviceX.NET/\"><text>Hello</text></Reply>";
+
+ @Autowired
+ private CamelEndpointMapping endpointMapping;
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ private MockWebServiceClient mockClient;
+
+ @BeforeEach
+ public void createClient() {
+ mockClient = MockWebServiceClient.createClient(applicationContext);
+ }
+
+ @Override
+ protected void bindToRegistry(Registry registry) throws Exception {
+ registry.bind("endpointMapping", this.endpointMapping);
+ }
+
+ @Test
+ public void nullBodyGivesEmptyResponse() throws Exception {
+ mockClient.sendRequest(withPayload(request("NullReply")))
+ .andExpect(noFault())
+ .andExpect((request, response) ->
assertNull(response.getPayloadSource(),
+ "A null reply body should give an empty SOAP body, not
the request payload"));
+ }
+
+ @Test
+ public void nullBodyFromSetBodyGivesEmptyResponse() throws Exception {
+ mockClient.sendRequest(withPayload(request("SetBodyNullReply")))
+ .andExpect(noFault())
+ .andExpect((request, response) ->
assertNull(response.getPayloadSource(),
+ "A null reply body should give an empty SOAP body, not
the request payload"));
+ }
+
+ @Test
+ public void outMessageWithoutBodyGivesEmptyResponse() throws Exception {
+ mockClient.sendRequest(withPayload(request("OutNoBodyReply")))
+ .andExpect(noFault())
+ .andExpect((request, response) ->
assertNull(response.getPayloadSource(),
+ "An OUT message without a body should give an empty
SOAP body, not the request payload"));
+ }
+
+ @Test
+ public void bodyNotConvertibleToSourceGivesFault() throws Exception {
+ mockClient.sendRequest(withPayload(request("MapReply")))
+ .andExpect(serverOrReceiverFault());
+ }
+
+ @Test
+ public void inputStreamBodyIsSentAsReply() throws Exception {
+ mockClient.sendRequest(withPayload(request("StreamReply")))
+ .andExpect(noFault())
+ .andExpect(payload(new StreamSource(new StringReader(REPLY))));
+ }
+
+ private static StreamSource request(String name) {
+ return new StreamSource(
+ new StringReader("<" + name + "
xmlns=\"http://www.webserviceX.NET/\"><symbol>GOOG</symbol></" + name + ">"));
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+
+ @Override
+ public void configure() throws Exception {
+
from("spring-ws:rootqname:{http://www.webserviceX.NET/}NullReply?endpointMapping=#endpointMapping")
+ .process(e -> e.getMessage().setBody(null));
+
+
from("spring-ws:rootqname:{http://www.webserviceX.NET/}SetBodyNullReply?endpointMapping=#endpointMapping")
+ .setBody(constant(null));
+
+
from("spring-ws:rootqname:{http://www.webserviceX.NET/}OutNoBodyReply?endpointMapping=#endpointMapping")
+ .process(e -> e.getOut().setHeader("foo", "bar"));
+
+
from("spring-ws:rootqname:{http://www.webserviceX.NET/}MapReply?endpointMapping=#endpointMapping")
+ .setBody(constant(Map.of("text", "Hello")));
+
+
from("spring-ws:rootqname:{http://www.webserviceX.NET/}StreamReply?endpointMapping=#endpointMapping")
+ .process(e -> e.getMessage()
+ .setBody(new
ByteArrayInputStream(REPLY.getBytes(StandardCharsets.UTF_8))));
+ }
+ };
+ }
+}
diff --git
a/components/camel-spring-parent/camel-spring-ws/src/test/java/org/apache/camel/component/spring/ws/ProducerLocalRouteTest.java
b/components/camel-spring-parent/camel-spring-ws/src/test/java/org/apache/camel/component/spring/ws/ProducerLocalRouteTest.java
index 64d06f468765..3a90d113985e 100644
---
a/components/camel-spring-parent/camel-spring-ws/src/test/java/org/apache/camel/component/spring/ws/ProducerLocalRouteTest.java
+++
b/components/camel-spring-parent/camel-spring-ws/src/test/java/org/apache/camel/component/spring/ws/ProducerLocalRouteTest.java
@@ -16,6 +16,12 @@
*/
package org.apache.camel.component.spring.ws;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
import javax.xml.transform.Source;
import org.apache.camel.EndpointInject;
@@ -27,6 +33,7 @@ import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.spring.junit6.CamelSpringTest;
import org.apache.camel.util.xml.StringSource;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
import org.springframework.test.context.ContextConfiguration;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -50,6 +57,12 @@ public class ProducerLocalRouteTest {
@EndpointInject("mock:inOnly")
private MockEndpoint inOnlyEndpoint;
+ @EndpointInject("mock:fileResult")
+ private MockEndpoint fileResultEndpoint;
+
+ @TempDir
+ private Path tempDir;
+
@Test
public void consumeStockQuoteWebserviceWithDefaultTemplate() throws
Exception {
Object result =
template.requestBody("direct:stockQuoteWebserviceWithDefaultTemplate",
xmlRequestForGoogleStockQuote);
@@ -85,6 +98,38 @@ public class ProducerLocalRouteTest {
assertTrue(result instanceof Source);
}
+ @Test
+ public void consumeStockQuoteWebserviceWithFileInput() throws Exception {
+ File file = tempDir.resolve("request.xml").toFile();
+ Files.writeString(file.toPath(), xmlRequestForGoogleStockQuote);
+
+ Object result =
template.requestBody("direct:stockQuoteWebserviceAsString", file);
+
+ assertTrue(result instanceof String);
+ assertTrue(((String) result).contains("Google Inc."));
+ }
+
+ @Test
+ public void consumeStockQuoteWebserviceFromFileConsumer() throws Exception
{
+ fileResultEndpoint.expectedMessageCount(1);
+ fileResultEndpoint.message(0).body().contains("Google Inc.");
+
+ Path dir = Path.of("target/data/spring-ws-file-input");
+ Files.createDirectories(dir);
+ Files.writeString(dir.resolve("request.xml"),
xmlRequestForGoogleStockQuote);
+
+ fileResultEndpoint.assertIsSatisfied();
+ }
+
+ @Test
+ public void consumeStockQuoteWebserviceWithInputStreamInputNoStreamCache()
throws Exception {
+ Object result =
template.requestBody("direct:stockQuoteWebserviceNoStreamCache",
+ new
ByteArrayInputStream(xmlRequestForGoogleStockQuote.getBytes(StandardCharsets.UTF_8)));
+
+ assertTrue(result instanceof String);
+ assertTrue(((String) result).contains("Google Inc."));
+ }
+
@Test
public void consumeStockQuoteWebserviceWithNonDefaultMessageFactory()
throws Exception {
Object result =
template.requestBody("direct:stockQuoteWebserviceWithNonDefaultMessageFactory",
diff --git
a/components/camel-spring-parent/camel-spring-ws/src/test/resources/org/apache/camel/component/spring/ws/ConsumerReplyBodyTest-context.xml
b/components/camel-spring-parent/camel-spring-ws/src/test/resources/org/apache/camel/component/spring/ws/ConsumerReplyBodyTest-context.xml
new file mode 100644
index 000000000000..84a8c610a205
--- /dev/null
+++
b/components/camel-spring-parent/camel-spring-ws/src/test/resources/org/apache/camel/component/spring/ws/ConsumerReplyBodyTest-context.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+ <bean id="endpointMapping"
+
class="org.apache.camel.component.spring.ws.bean.CamelEndpointMapping"/>
+
+</beans>
diff --git
a/components/camel-spring-parent/camel-spring-ws/src/test/resources/org/apache/camel/component/spring/ws/ProducerLocalRouteTest-context.xml
b/components/camel-spring-parent/camel-spring-ws/src/test/resources/org/apache/camel/component/spring/ws/ProducerLocalRouteTest-context.xml
index 893cbae41e9d..95dc9e70c667 100644
---
a/components/camel-spring-parent/camel-spring-ws/src/test/resources/org/apache/camel/component/spring/ws/ProducerLocalRouteTest-context.xml
+++
b/components/camel-spring-parent/camel-spring-ws/src/test/resources/org/apache/camel/component/spring/ws/ProducerLocalRouteTest-context.xml
@@ -61,6 +61,17 @@
<convertBodyTo type="java.lang.String"/>
<to uri="mock:inOnly" />
</route>
+ <route streamCache="false">
+ <from uri="direct:stockQuoteWebserviceNoStreamCache"/>
+ <to
uri="spring-ws:http://localhost?webServiceTemplate=#webServiceTemplate&soapAction=http://www.stockquotes.edu/GetQuote"/>
+ <convertBodyTo type="java.lang.String"/>
+ </route>
+ <route>
+ <from
uri="file:target/data/spring-ws-file-input?initialDelay=0&delay=100"/>
+ <to
uri="spring-ws:http://localhost?webServiceTemplate=#webServiceTemplate&soapAction=http://www.stockquotes.edu/GetQuote"/>
+ <convertBodyTo type="java.lang.String"/>
+ <to uri="mock:fileResult"/>
+ </route>
<!-- consumer route (providing the actual web service) -->
<route>
<from
uri="spring-ws:soapaction:http://www.stockquotes.edu/GetQuote?endpointMapping=#endpointMapping"/>
@@ -83,4 +94,4 @@
</property>
</bean>
-</beans>
\ No newline at end of file
+</beans>
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index a5bf98a4b023..96c851592919 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -3951,6 +3951,19 @@ The consumer now gives a message that its serializer
cannot deserialize, such as
route as a `byte[]`. Previously the message was dropped with a WARN. A failed
exchange of the consumer is now handed to
its exception handler.
+=== camel-spring-ws - the reply of a consumer, and File and stream bodies of
the producer
+
+A `spring-ws` consumer route that sets the body to `null` in a processor, such
as with
+`exchange.getMessage().setBody(null)`, now answers with an empty SOAP body.
Previously the message created its body
+again from the request, so the request payload was sent back. Likewise, an OUT
message that the route creates with
+`exchange.getOut()` no longer starts with the request payload as its body.
+
+A reply body that does not convert to a `javax.xml.transform.Source`, such as
a `Map`, now gives a SOAP fault with the
+conversion error. Previously it gave an empty SOAP body. A reply body that is
an `InputStream` is now sent as XML.
+
+The `spring-ws` producer now sends a `File` body, the file of a `file` or
`ftp` consumer, and an `InputStream` body
+(also when stream caching is off) as XML. Previously these failed with an
`InvalidPayloadException`.
+
=== camel-couchbase - the document id, the operation option and the bodies of
CCB_PUT
The `couchbase` producer now uses the `key` option as the document id when the
message has no `CamelCouchbaseId`