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");
+ }
+ };
+ }
+}