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 af23d08150fd CAMEL-26278: camel-hazelcast - the hazelcast-seda 
consumer restores a transferred exchange only with transferExchange=true and 
otherwise takes its body (#29310)
af23d08150fd is described below

commit af23d08150fdf60c73d50151e607519e50a54223
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Nov 6 10:29:34 2026 +0100

    CAMEL-26278: camel-hazelcast - the hazelcast-seda consumer restores a 
transferred exchange only with transferExchange=true and otherwise takes its 
body (#29310)
    
    Signed-off-by: Andrea Cosentino <[email protected]>
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 .../camel/catalog/components/hazelcast-seda.json   |  4 +-
 .../catalog/docs/hazelcast-seda-component.adoc     | 27 ++++++++
 .../component/hazelcast/seda/hazelcast-seda.json   |  4 +-
 .../src/main/docs/hazelcast-seda-component.adoc    | 27 ++++++++
 .../hazelcast/seda/HazelcastSedaConfiguration.java |  3 +-
 .../hazelcast/seda/HazelcastSedaConsumer.java      | 27 +++++++-
 .../hazelcast/seda/HazelcastSedaEndpoint.java      |  5 +-
 .../HazelcastSedaTransferExchangeTest.java         | 80 ++++++++++++++++++++--
 .../ROOT/pages/camel-4x-upgrade-guide-4_18.adoc    | 11 +++
 .../ROOT/pages/camel-4x-upgrade-guide-4_22.adoc    | 11 +++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    | 11 +++
 .../dsl/HazelcastSedaEndpointBuilderFactory.java   | 30 ++++++--
 12 files changed, 220 insertions(+), 20 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hazelcast-seda.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hazelcast-seda.json
index 7f0eba6c65c0..98b00a8ba165 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hazelcast-seda.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/hazelcast-seda.json
@@ -31,7 +31,7 @@
     "hazelcastMode": { "index": 4, "kind": "property", "displayName": 
"Hazelcast Mode", "group": "advanced", "label": "advanced", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "node", "description": 
"The hazelcast mode reference which kind of instance should be used. If you 
don't specify the mode, then the node mode will be the default." }
   },
   "bodyTypes": {
-    "consumerOut": { "carriers": [ "text", "bytes", "file", "value", "map", 
"list", "pojo" ], "description": "The body the producer put on the Hazelcast 
queue, as Hazelcast deserializes it: a body that is not Serializable, such as a 
stream, arrives as bytes. With transferExchange=true on the producer the 
headers and exchange properties come along" },
+    "consumerOut": { "carriers": [ "text", "bytes", "file", "value", "map", 
"list", "pojo" ], "description": "The body the producer put on the Hazelcast 
queue, as Hazelcast deserializes it: a body that is not Serializable, such as a 
stream, arrives as bytes. With transferExchange=true on both the producer and 
the consumer the headers and exchange properties come along: a consumer without 
it takes only the body" },
     "producerIn": { "carriers": [ "text", "bytes", "stream", "file", "value", 
"map", "list", "pojo" ], "description": "A Serializable body goes on the queue 
as is, and another one converted to bytes, so a stream works, but a POJO that 
does not convert to bytes fails, as does no body" },
     "producerOut": { "carriers": [ "unchanged" ], "description": "The producer 
puts the message on the queue and does not wait for the consumer, also for a 
message that expects a reply (InOut)" }
   },
@@ -49,6 +49,6 @@
     "onErrorDelay": { "index": 10, "kind": "parameter", "displayName": "On 
Error Delay", "group": "seda", "label": "seda", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 1000, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "Milliseconds before 
consumer continues polling after an error has occurred." },
     "pollTimeout": { "index": 11, "kind": "parameter", "displayName": "Poll 
Timeout", "group": "seda", "label": "seda", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 1000, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "The timeout used when 
consuming from the SEDA queue. When a timeout occurs, the consum [...]
     "transacted": { "index": 12, "kind": "parameter", "displayName": 
"Transacted", "group": "seda", "label": "seda", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "If set to true then the 
consumer runs in transaction mode, where the messages in the [...]
-    "transferExchange": { "index": 13, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "seda", "label": "seda", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "security": "insecure:serialization", "defaultValue": 
false, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "If set to true the whole 
Exchange [...]
+    "transferExchange": { "index": 13, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "seda", "label": "seda", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "security": "insecure:serialization", "defaultValue": 
false, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "If set to true the whole 
Exchange [...]
   }
 }
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hazelcast-seda-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hazelcast-seda-component.adoc
index 550d5c0c922f..a84eb7946866 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hazelcast-seda-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/hazelcast-seda-component.adoc
@@ -101,3 +101,30 @@ YAML::
 ----
 ====
 
+== Transferring the whole exchange
+
+By default only the message body goes on the queue. With 
`transferExchange=true` the producer puts the whole exchange
+on the queue: the body, and the headers and exchange properties whose values 
are text, numbers, booleans or dates. A
+consumer with `transferExchange=true` restores them. A consumer without the 
option takes only the body of such an
+exchange: set `transferExchange=true` on both endpoints to keep the headers 
and exchange properties.
+
+[source,yaml]
+----
+- route:
+    from:
+      uri: direct:foo
+      steps:
+        - to:
+            uri: hazelcast-seda:foo
+            parameters:
+              transferExchange: true
+- route:
+    from:
+      uri: hazelcast-seda:foo
+      parameters:
+        transferExchange: true
+      steps:
+        - to:
+            uri: mock:result
+----
+
diff --git 
a/components/camel-hazelcast/src/generated/resources/META-INF/org/apache/camel/component/hazelcast/seda/hazelcast-seda.json
 
b/components/camel-hazelcast/src/generated/resources/META-INF/org/apache/camel/component/hazelcast/seda/hazelcast-seda.json
index 7f0eba6c65c0..98b00a8ba165 100644
--- 
a/components/camel-hazelcast/src/generated/resources/META-INF/org/apache/camel/component/hazelcast/seda/hazelcast-seda.json
+++ 
b/components/camel-hazelcast/src/generated/resources/META-INF/org/apache/camel/component/hazelcast/seda/hazelcast-seda.json
@@ -31,7 +31,7 @@
     "hazelcastMode": { "index": 4, "kind": "property", "displayName": 
"Hazelcast Mode", "group": "advanced", "label": "advanced", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "node", "description": 
"The hazelcast mode reference which kind of instance should be used. If you 
don't specify the mode, then the node mode will be the default." }
   },
   "bodyTypes": {
-    "consumerOut": { "carriers": [ "text", "bytes", "file", "value", "map", 
"list", "pojo" ], "description": "The body the producer put on the Hazelcast 
queue, as Hazelcast deserializes it: a body that is not Serializable, such as a 
stream, arrives as bytes. With transferExchange=true on the producer the 
headers and exchange properties come along" },
+    "consumerOut": { "carriers": [ "text", "bytes", "file", "value", "map", 
"list", "pojo" ], "description": "The body the producer put on the Hazelcast 
queue, as Hazelcast deserializes it: a body that is not Serializable, such as a 
stream, arrives as bytes. With transferExchange=true on both the producer and 
the consumer the headers and exchange properties come along: a consumer without 
it takes only the body" },
     "producerIn": { "carriers": [ "text", "bytes", "stream", "file", "value", 
"map", "list", "pojo" ], "description": "A Serializable body goes on the queue 
as is, and another one converted to bytes, so a stream works, but a POJO that 
does not convert to bytes fails, as does no body" },
     "producerOut": { "carriers": [ "unchanged" ], "description": "The producer 
puts the message on the queue and does not wait for the consumer, also for a 
message that expects a reply (InOut)" }
   },
@@ -49,6 +49,6 @@
     "onErrorDelay": { "index": 10, "kind": "parameter", "displayName": "On 
Error Delay", "group": "seda", "label": "seda", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 1000, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "Milliseconds before 
consumer continues polling after an error has occurred." },
     "pollTimeout": { "index": 11, "kind": "parameter", "displayName": "Poll 
Timeout", "group": "seda", "label": "seda", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 1000, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "The timeout used when 
consuming from the SEDA queue. When a timeout occurs, the consum [...]
     "transacted": { "index": 12, "kind": "parameter", "displayName": 
"Transacted", "group": "seda", "label": "seda", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "If set to true then the 
consumer runs in transaction mode, where the messages in the [...]
-    "transferExchange": { "index": 13, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "seda", "label": "seda", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "security": "insecure:serialization", "defaultValue": 
false, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "If set to true the whole 
Exchange [...]
+    "transferExchange": { "index": 13, "kind": "parameter", "displayName": 
"Transfer Exchange", "group": "seda", "label": "seda", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "security": "insecure:serialization", "defaultValue": 
false, "configurationClass": 
"org.apache.camel.component.hazelcast.seda.HazelcastSedaConfiguration", 
"configurationField": "configuration", "description": "If set to true the whole 
Exchange [...]
   }
 }
diff --git 
a/components/camel-hazelcast/src/main/docs/hazelcast-seda-component.adoc 
b/components/camel-hazelcast/src/main/docs/hazelcast-seda-component.adoc
index 550d5c0c922f..a84eb7946866 100644
--- a/components/camel-hazelcast/src/main/docs/hazelcast-seda-component.adoc
+++ b/components/camel-hazelcast/src/main/docs/hazelcast-seda-component.adoc
@@ -101,3 +101,30 @@ YAML::
 ----
 ====
 
+== Transferring the whole exchange
+
+By default only the message body goes on the queue. With 
`transferExchange=true` the producer puts the whole exchange
+on the queue: the body, and the headers and exchange properties whose values 
are text, numbers, booleans or dates. A
+consumer with `transferExchange=true` restores them. A consumer without the 
option takes only the body of such an
+exchange: set `transferExchange=true` on both endpoints to keep the headers 
and exchange properties.
+
+[source,yaml]
+----
+- route:
+    from:
+      uri: direct:foo
+      steps:
+        - to:
+            uri: hazelcast-seda:foo
+            parameters:
+              transferExchange: true
+- route:
+    from:
+      uri: hazelcast-seda:foo
+      parameters:
+        transferExchange: true
+      steps:
+        - to:
+            uri: mock:result
+----
+
diff --git 
a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConfiguration.java
 
b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConfiguration.java
index 9c5be6dcd05d..53cef537ba1d 100644
--- 
a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConfiguration.java
+++ 
b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConfiguration.java
@@ -109,7 +109,8 @@ public class HazelcastSedaConfiguration {
 
     /**
      * If set to true the whole Exchange will be transfered. If header or body 
contains not serializable objects, they
-     * will be skipped.
+     * will be skipped. Set it on both the producer and the consumer: the 
producer puts the whole Exchange on the queue,
+     * and the consumer restores its headers and exchange properties. A 
consumer without it takes only the body.
      */
     public void setTransferExchange(boolean transferExchange) {
         this.transferExchange = transferExchange;
diff --git 
a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
 
b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
index 27e733e1be96..61f504fc936f 100644
--- 
a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
+++ 
b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
@@ -31,6 +31,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.support.AsyncProcessorConverterHelper;
 import org.apache.camel.support.DefaultConsumer;
+import org.apache.camel.support.DefaultExchange;
 import org.apache.camel.support.DefaultExchangeHolder;
 import org.apache.camel.support.task.Tasks;
 import org.apache.camel.support.task.budget.Budgets;
@@ -51,6 +52,7 @@ public class HazelcastSedaConsumer extends DefaultConsumer 
implements Runnable {
     private final AsyncProcessor processor;
     private ExecutorService executor;
     private ScheduledExecutorService taskExecutor;
+    private volatile boolean transferredExchangeLogged;
 
     public HazelcastSedaConsumer(final Endpoint endpoint, final Processor 
processor) {
         super(endpoint, processor);
@@ -115,8 +117,8 @@ public class HazelcastSedaConsumer extends DefaultConsumer 
implements Runnable {
                         TimeUnit.MILLISECONDS);
 
                 if (body != null) {
-                    if (body instanceof DefaultExchangeHolder 
defaultExchangeHolder) {
-                        DefaultExchangeHolder.unmarshal(exchange, 
defaultExchangeHolder);
+                    if (body instanceof DefaultExchangeHolder holder) {
+                        takeTransferredExchange(exchange, holder);
                     } else {
                         exchange.getIn().setBody(body);
                     }
@@ -190,6 +192,27 @@ public class HazelcastSedaConsumer extends DefaultConsumer 
implements Runnable {
         }
     }
 
+    /**
+     * An exchange that a producer with transferExchange=true put on the 
queue: the consumer restores its headers and
+     * exchange properties only when it has transferExchange=true as well, and 
otherwise takes only its body.
+     */
+    private void takeTransferredExchange(Exchange exchange, 
DefaultExchangeHolder holder) {
+        if (endpoint.getConfiguration().isTransferExchange()) {
+            DefaultExchangeHolder.unmarshal(exchange, holder);
+            return;
+        }
+        if (!transferredExchangeLogged) {
+            transferredExchangeLogged = true;
+            LOG.warn("The queue {} holds an exchange that a producer with 
transferExchange=true put on it, but this consumer"
+                     + " has transferExchange=false: it takes only the body of 
such an exchange, without its headers and"
+                     + " exchange properties. Set transferExchange=true on the 
consumer to restore them.",
+                    endpoint.getConfiguration().getQueueName());
+        }
+        Exchange transferred = new DefaultExchange(endpoint.getCamelContext());
+        DefaultExchangeHolder.unmarshal(transferred, holder);
+        exchange.getIn().setBody(transferred.getIn().getBody());
+    }
+
     private void onExchangeDone(Exchange exchange, TransactionContext txc) {
         // a rollback only exchange (without an exception) did not complete 
successfully either
         boolean rollback = exchange.getException() != null || 
exchange.isRollbackOnly()
diff --git 
a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaEndpoint.java
 
b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaEndpoint.java
index e1ab848af547..1eb975f1ec0f 100644
--- 
a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaEndpoint.java
+++ 
b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaEndpoint.java
@@ -46,8 +46,9 @@ import static 
org.apache.camel.component.hazelcast.HazelcastConstants.SCHEME_SED
         Carrier.TEXT, Carrier.BYTES, Carrier.FILE, Carrier.VALUE, Carrier.MAP, 
Carrier.LIST, Carrier.POJO },
                                    description = "The body the producer put on 
the Hazelcast queue, as Hazelcast "
                                                  + "deserializes it: a body 
that is not Serializable, such as a "
-                                                 + "stream, arrives as bytes. 
With transferExchange=true on the "
-                                                 + "producer the headers and 
exchange properties come along"),
+                                                 + "stream, arrives as bytes. 
With transferExchange=true on both the "
+                                                 + "producer and the consumer 
the headers and exchange properties "
+                                                 + "come along: a consumer 
without it takes only the body"),
            producerIn = @BodyType(value = {
                    Carrier.TEXT, Carrier.BYTES, Carrier.STREAM, Carrier.FILE, 
Carrier.VALUE, Carrier.MAP, Carrier.LIST,
                    Carrier.POJO },
diff --git 
a/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSedaTransferExchangeTest.java
 
b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSedaTransferExchangeTest.java
index df51b1e44bc6..129d29899c31 100644
--- 
a/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSedaTransferExchangeTest.java
+++ 
b/components/camel-hazelcast/src/test/java/org/apache/camel/component/hazelcast/HazelcastSedaTransferExchangeTest.java
@@ -23,6 +23,7 @@ import org.apache.camel.EndpointInject;
 import org.apache.camel.Exchange;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.support.DefaultExchangeHolder;
 import org.apache.camel.test.infra.common.TestEntityNameGenerator;
 import org.apache.camel.test.infra.hazelcast.services.HazelcastService;
 import org.apache.camel.test.infra.hazelcast.services.HazelcastServiceFactory;
@@ -34,6 +35,8 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestInstance;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import static org.junit.jupiter.api.Assertions.assertNull;
+
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public class HazelcastSedaTransferExchangeTest extends CamelTestSupport {
 
@@ -46,6 +49,12 @@ public class HazelcastSedaTransferExchangeTest extends 
CamelTestSupport {
     @EndpointInject("mock:result")
     private MockEndpoint mock;
 
+    @EndpointInject("mock:transferred")
+    private MockEndpoint transferred;
+
+    @EndpointInject("mock:bodyOnly")
+    private MockEndpoint bodyOnly;
+
     private HazelcastInstance hazelcastInstance;
 
     @BeforeAll
@@ -56,6 +65,8 @@ public class HazelcastSedaTransferExchangeTest extends 
CamelTestSupport {
     @AfterEach
     public void afterEach() {
         mock.reset();
+        transferred.reset();
+        bodyOnly.reset();
     }
 
     @AfterAll
@@ -69,18 +80,69 @@ public class HazelcastSedaTransferExchangeTest extends 
CamelTestSupport {
     public void testExchangeTransferEnabled() throws InterruptedException {
         final String value = "CAMEL-3983";
 
-        mock.expectedMessageCount(1);
-        mock.expectedBodiesReceived("test");
-        mock.expectedHeaderReceived("test", value);
+        transferred.expectedMessageCount(1);
+        transferred.expectedBodiesReceived("test");
+        transferred.expectedHeaderReceived("test", value);
+        transferred.expectedPropertyReceived("test", value);
 
         Exchange exchange = createExchangeWithBody("test");
         exchange.getIn().setHeader("test", value);
+        exchange.setProperty("test", value);
 
         template.send("direct:foobar", exchange);
 
         MockEndpoint.assertIsSatisfied(context);
     }
 
+    @Test
+    void 
transferredExchangeGivesOnlyItsBodyToAConsumerWithoutTransferExchange() throws 
InterruptedException {
+        bodyOnly.expectedMessageCount(1);
+        bodyOnly.expectedBodiesReceived("test");
+        bodyOnly.expectedNoHeaderReceived();
+
+        Exchange exchange = createExchangeWithBody("test");
+        exchange.getIn().setHeader("test", "Not propagated");
+        exchange.setProperty("test", "Not propagated");
+
+        template.send("direct:bodyOnly", exchange);
+
+        MockEndpoint.assertIsSatisfied(context);
+        assertNull(bodyOnly.getReceivedExchanges().get(0).getProperty("test"));
+    }
+
+    @Test
+    void holderOnTheQueueGivesOnlyItsBodyWithoutTransferExchange() throws 
InterruptedException {
+        bodyOnly.expectedMessageCount(1);
+        bodyOnly.expectedBodiesReceived("held");
+        bodyOnly.expectedNoHeaderReceived();
+
+        hazelcastInstance.getQueue("body-only").add(holder("held"));
+
+        MockEndpoint.assertIsSatisfied(context);
+        Exchange received = bodyOnly.getReceivedExchanges().get(0);
+        assertNull(received.getProperty("test"));
+        assertNull(received.getException());
+    }
+
+    @Test
+    void holderOnTheQueueGivesItsHeadersAndPropertiesWithTransferExchange() 
throws InterruptedException {
+        transferred.expectedMessageCount(1);
+        transferred.expectedBodiesReceived("held");
+        transferred.expectedHeaderReceived("test", "held header");
+        transferred.expectedPropertyReceived("test", "held property");
+
+        hazelcastInstance.getQueue("transferred").add(holder("held"));
+
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    private DefaultExchangeHolder holder(String body) {
+        Exchange exchange = createExchangeWithBody(body);
+        exchange.getIn().setHeader("test", "held header");
+        exchange.setProperty("test", "held property");
+        return DefaultExchangeHolder.marshal(exchange);
+    }
+
     @Test
     public void testExchangeTransferDisabled() throws InterruptedException {
         mock.expectedMessageCount(1);
@@ -110,9 +172,17 @@ public class HazelcastSedaTransferExchangeTest extends 
CamelTestSupport {
             public void configure() {
                 from("direct:foo").to("hazelcast-seda:foo");
 
-                
from("direct:foobar").to("hazelcast-seda:foo?transferExchange=true");
-
                 from("hazelcast-seda:foo").to("mock:result");
+
+                // transferExchange on both sides: the headers and exchange 
properties come along
+                
from("direct:foobar").to("hazelcast-seda:transferred?transferExchange=true");
+
+                
from("hazelcast-seda:transferred?transferExchange=true").to("mock:transferred");
+
+                // transferExchange only on the producer: the consumer takes 
only the body
+                
from("direct:bodyOnly").to("hazelcast-seda:body-only?transferExchange=true");
+
+                from("hazelcast-seda:body-only").to("mock:bodyOnly");
             }
         };
     }
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc
index 07b80d388019..a1fcefc37f1b 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc
@@ -72,6 +72,17 @@ Checkpoint failures from the timer are now logged at `WARN` 
level with the full
 at `DEBUG` level with the message only. Checkpoint failures triggered by batch 
size are still logged at
 `WARN`.
 
+=== camel-hazelcast - the hazelcast-seda consumer restores a transferred 
exchange only with transferExchange=true
+
+A `hazelcast-seda` consumer now restores the headers and exchange properties 
of an exchange that a producer with
+`transferExchange=true` put on the queue only when the consumer has 
`transferExchange=true` as well. A consumer without
+the option, the default, now takes only the body of such an exchange, as it 
does for any other item of the queue, and
+logs a warning the first time. Before, the consumer restored the headers and 
exchange properties whatever its
+`transferExchange` option said.
+
+Set `transferExchange=true` on both the producer and the consumer endpoints to 
keep transferring the headers and
+exchange properties.
+
 === camel-lra - only an LRA hosted by the configured coordinator is joined
 
 The LRA saga service now joins, completes or compensates an LRA only when its 
URL is under the configured LRA
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
index 4c8a35dc8da5..51be81c771df 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
@@ -70,6 +70,17 @@ scheduled time of its window, but before the (late) timer 
has run, joins that wi
 checkpointed by that timer. Before, such an event always started a new window, 
so `timeout` was practically never
 set. Routes that read this header can now see `timeout` as well as `size`.
 
+=== camel-hazelcast - the hazelcast-seda consumer restores a transferred 
exchange only with transferExchange=true
+
+A `hazelcast-seda` consumer now restores the headers and exchange properties 
of an exchange that a producer with
+`transferExchange=true` put on the queue only when the consumer has 
`transferExchange=true` as well. A consumer without
+the option, the default, now takes only the body of such an exchange, as it 
does for any other item of the queue, and
+logs a warning the first time. Before, the consumer restored the headers and 
exchange properties whatever its
+`transferExchange` option said.
+
+Set `transferExchange=true` on both the producer and the consumer endpoints to 
keep transferring the headers and
+exchange properties.
+
 === camel-milo - the OPC UA client validates the server certificate
 
 When the endpoint it selects uses a security policy other than `None`, the 
`milo-client` and `milo-browse` components
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 7fdfc73bea93..4ff53d3c933a 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
@@ -6282,6 +6282,17 @@ Previously the newest message was left out.
 The `stream:header` producer now fails with a `NoSuchHeaderException` when the 
`stream` header is missing or is not an
 `OutputStream`. Previously it failed with a `NullPointerException`, or did 
nothing when the body was null.
 
+=== camel-hazelcast - the hazelcast-seda consumer restores a transferred 
exchange only with transferExchange=true
+
+A `hazelcast-seda` consumer now restores the headers and exchange properties 
of an exchange that a producer with
+`transferExchange=true` put on the queue only when the consumer has 
`transferExchange=true` as well. A consumer without
+the option, the default, now takes only the body of such an exchange, as it 
does for any other item of the queue, and
+logs a warning the first time. Before, the consumer restored the headers and 
exchange properties whatever its
+`transferExchange` option said.
+
+Set `transferExchange=true` on both the producer and the consumer endpoints to 
keep transferring the headers and
+exchange properties.
+
 === camel-knative - a structured CloudEvent whose Content-Type has parameters
 
 The consumer now finds the content mode of a CloudEvent by the media type of 
the `Content-Type` header, ignoring its
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HazelcastSedaEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HazelcastSedaEndpointBuilderFactory.java
index 75ae9dc56bd9..1e4f9b50b648 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HazelcastSedaEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/HazelcastSedaEndpointBuilderFactory.java
@@ -289,7 +289,10 @@ public interface HazelcastSedaEndpointBuilderFactory {
         }
         /**
          * If set to true the whole Exchange will be transfered. If header or
-         * body contains not serializable objects, they will be skipped.
+         * body contains not serializable objects, they will be skipped. Set it
+         * on both the producer and the consumer: the producer puts the whole
+         * Exchange on the queue, and the consumer restores its headers and
+         * exchange properties. A consumer without it takes only the body.
          * 
          * The option is a: <code>boolean</code> type.
          * 
@@ -305,7 +308,10 @@ public interface HazelcastSedaEndpointBuilderFactory {
         }
         /**
          * If set to true the whole Exchange will be transfered. If header or
-         * body contains not serializable objects, they will be skipped.
+         * body contains not serializable objects, they will be skipped. Set it
+         * on both the producer and the consumer: the producer puts the whole
+         * Exchange on the queue, and the consumer restores its headers and
+         * exchange properties. A consumer without it takes only the body.
          * 
          * The option will be converted to a <code>boolean</code> type.
          * 
@@ -704,7 +710,10 @@ public interface HazelcastSedaEndpointBuilderFactory {
         }
         /**
          * If set to true the whole Exchange will be transfered. If header or
-         * body contains not serializable objects, they will be skipped.
+         * body contains not serializable objects, they will be skipped. Set it
+         * on both the producer and the consumer: the producer puts the whole
+         * Exchange on the queue, and the consumer restores its headers and
+         * exchange properties. A consumer without it takes only the body.
          * 
          * The option is a: <code>boolean</code> type.
          * 
@@ -720,7 +729,10 @@ public interface HazelcastSedaEndpointBuilderFactory {
         }
         /**
          * If set to true the whole Exchange will be transfered. If header or
-         * body contains not serializable objects, they will be skipped.
+         * body contains not serializable objects, they will be skipped. Set it
+         * on both the producer and the consumer: the producer puts the whole
+         * Exchange on the queue, and the consumer restores its headers and
+         * exchange properties. A consumer without it takes only the body.
          * 
          * The option will be converted to a <code>boolean</code> type.
          * 
@@ -1048,7 +1060,10 @@ public interface HazelcastSedaEndpointBuilderFactory {
         }
         /**
          * If set to true the whole Exchange will be transfered. If header or
-         * body contains not serializable objects, they will be skipped.
+         * body contains not serializable objects, they will be skipped. Set it
+         * on both the producer and the consumer: the producer puts the whole
+         * Exchange on the queue, and the consumer restores its headers and
+         * exchange properties. A consumer without it takes only the body.
          * 
          * The option is a: <code>boolean</code> type.
          * 
@@ -1064,7 +1079,10 @@ public interface HazelcastSedaEndpointBuilderFactory {
         }
         /**
          * If set to true the whole Exchange will be transfered. If header or
-         * body contains not serializable objects, they will be skipped.
+         * body contains not serializable objects, they will be skipped. Set it
+         * on both the producer and the consumer: the producer puts the whole
+         * Exchange on the queue, and the consumer restores its headers and
+         * exchange properties. A consumer without it takes only the body.
          * 
          * The option will be converted to a <code>boolean</code> type.
          * 

Reply via email to