This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch camel-4.22.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.22.x by this push:
     new 0fefb4093c18 [backport camel-4.22.x] CAMEL-25860: camel-core - 
pollEnrich: after a timeout, the body stays null also for a message that 
creates its body on demand (#28164)
0fefb4093c18 is described below

commit 0fefb4093c18cda030f5675a56546941f9d8208a
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Oct 20 12:22:46 2026 +0200

    [backport camel-4.22.x] CAMEL-25860: camel-core - pollEnrich: after a 
timeout, the body stays null also for a message that creates its body on demand 
(#28164)
    
    CAMEL-25860: camel-core - pollEnrich: after a timeout, the body stays null 
also for a message that creates its body on demand
    
    After a timeout, the default aggregation sets the body to null, but a 
message that creates its body on demand (the
    message of a file consumer creates it from its file; JMS, mail and HTTP 
messages from their payload) brought it back
    on the next read, so the body, or the variable of variableReceive, was the 
file of the exchange. The aggregation now
    uses a plain message with the same headers and attachments when the null 
body does not stick.
    
    
    Claude-Session: https://claude.ai/code/session_01STT6whBgK1AqsSsUKrnE8m
    (cherry picked from commit 9921926c3d87b3de350684e635089214af6906cc)
    
    Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
 .../org/apache/camel/processor/PollEnricher.java   |   9 ++
 .../enricher/PollEnrichTimeoutFileBodyTest.java    | 108 +++++++++++++++++++++
 2 files changed, 117 insertions(+)

diff --git 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/PollEnricher.java
 
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/PollEnricher.java
index debcbcfb9742..00ea62ba759a 100644
--- 
a/core/camel-core-processor/src/main/java/org/apache/camel/processor/PollEnricher.java
+++ 
b/core/camel-core-processor/src/main/java/org/apache/camel/processor/PollEnricher.java
@@ -32,6 +32,7 @@ import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePropertyKey;
 import org.apache.camel.Expression;
+import org.apache.camel.Message;
 import org.apache.camel.NoTypeConversionAvailableException;
 import org.apache.camel.PollingConsumer;
 import org.apache.camel.ResolveEndpointFailedException;
@@ -46,6 +47,7 @@ import org.apache.camel.spi.RouteIdAware;
 import org.apache.camel.spi.StepIdAware;
 import org.apache.camel.support.BridgeExceptionHandlerToErrorHandler;
 import org.apache.camel.support.DefaultConsumer;
+import org.apache.camel.support.DefaultMessage;
 import org.apache.camel.support.EndpointHelper;
 import org.apache.camel.support.EventDrivenPollingConsumer;
 import org.apache.camel.support.ExchangeHelper;
@@ -671,6 +673,13 @@ public class PollEnricher extends BaseProcessorSupport 
implements IdAware, Route
                 // and therefore we should set an empty body to indicate this 
fact
                 // but keep headers/attachments as we want to propagate those
                 oldExchange.getIn().setBody(null);
+                if (oldExchange.getIn().getBody() != null) {
+                    // a message that creates its body on demand brings it 
back, such as the message of a file
+                    // consumer, whose body is its file: a plain message with 
the same headers keeps the body empty
+                    Message empty = new DefaultMessage(oldExchange);
+                    empty.copyFromWithNewBody(oldExchange.getIn(), null);
+                    oldExchange.setIn(empty);
+                }
                 oldExchange.setOut(null);
             }
             return oldExchange;
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollEnrichTimeoutFileBodyTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollEnrichTimeoutFileBodyTest.java
new file mode 100644
index 000000000000..a5f5342136ed
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/processor/enricher/PollEnrichTimeoutFileBodyTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.processor.enricher;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.support.DefaultMessage;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * A pollEnrich that times out sets no body, also in a route that consumes 
files: the message of a file consumer creates
+ * its body from the file on demand, which brought the file of the exchange 
back as the body, or as the variable of
+ * variableReceive. The messages of JMS, mail and HTTP consumers create their 
body on demand as well.
+ */
+class PollEnrichTimeoutFileBodyTest extends ContextTestSupport {
+
+    @Test
+    void theBodyIsNullWhenNothingWasPolled() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:body");
+        mock.expectedMessageCount(1);
+
+        template.sendBodyAndHeader(fileUri("orders-body"), "ORD-1001", 
Exchange.FILE_NAME, "order-1001.json");
+
+        mock.assertIsSatisfied();
+        assertNull(mock.getReceivedExchanges().get(0).getMessage().getBody(), 
"nothing was polled, so no body");
+    }
+
+    @Test
+    void theVariableIsNullWhenNothingWasPolled() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:variable");
+        mock.expectedMessageCount(1);
+
+        template.sendBodyAndHeader(fileUri("orders-variable"), "ORD-1001", 
Exchange.FILE_NAME, "order-1001.json");
+
+        mock.assertIsSatisfied();
+        Exchange exchange = mock.getReceivedExchanges().get(0);
+        assertNull(exchange.getVariable("customer"), "nothing was polled, so 
no variable");
+        // the order is kept as the body
+        assertEquals("ORD-1001", exchange.getMessage().getBody(String.class));
+    }
+
+    @Test
+    void theBodyOfAMessageThatCreatesItOnDemandIsNull() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:demand");
+        mock.expectedMessageCount(1);
+
+        template.send("direct:demand", e -> e.setIn(new OnDemandMessage(e)));
+
+        mock.assertIsSatisfied();
+        Exchange exchange = mock.getReceivedExchanges().get(0);
+        assertNull(exchange.getMessage().getBody(), "nothing was polled, so no 
body");
+        assertEquals("ORD-1001", exchange.getMessage().getHeader("orderId"), 
"the headers are kept");
+    }
+
+    // creates its body on demand, as the message of a JMS or mail consumer 
does
+    private static class OnDemandMessage extends DefaultMessage {
+
+        OnDemandMessage(Exchange exchange) {
+            super(exchange);
+            setHeader("orderId", "ORD-1001");
+        }
+
+        @Override
+        protected Object createBody() {
+            return "the payload of the consumer";
+        }
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from(fileUri("orders-body?initialDelay=0&delay=10"))
+                        
.pollEnrich().simple(fileUri("customers?fileName=C-482.json")).timeout(100)
+                        .to("mock:body");
+
+                from(fileUri("orders-variable?initialDelay=0&delay=10"))
+                        
.pollEnrich().simple(fileUri("customers?fileName=C-482.json")).timeout(100)
+                        .variableReceive("customer")
+                        .to("mock:variable");
+
+                from("direct:demand")
+                        
.pollEnrich().simple(fileUri("customers?fileName=C-482.json")).timeout(100)
+                        .to("mock:demand");
+            }
+        };
+    }
+}

Reply via email to