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

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

commit 82410ac524e9f862890c7fbdd5152dc30e1641cd
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Thu Apr 24 20:26:29 2025 +0200

    CAMEL-22018: camel-core - Exchange.getVariables should include message 
headers
---
 .../language/groovy/GroovyExpressionTest.java      | 13 +++++++++
 .../src/main/java/org/apache/camel/Exchange.java   |  4 +--
 .../src/main/java/org/apache/camel/Variables.java  |  2 +-
 .../bean/BeanWithVariablesAndBodyInject3Test.java  | 34 +++++-----------------
 .../org/apache/camel/language/VariableTest.java    |  8 +++++
 .../apache/camel/language/simple/SimpleTest.java   |  8 ++---
 .../org/apache/camel/util/ExchangeHelperTest.java  |  6 ++--
 .../org/apache/camel/support/ExchangeHelper.java   |  2 +-
 .../camel/support/ExchangeVariableRepository.java  | 23 +++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_10.adoc    |  2 ++
 .../ROOT/pages/camel-4x-upgrade-guide-4_12.adoc    |  2 ++
 11 files changed, 67 insertions(+), 37 deletions(-)

diff --git 
a/components/camel-groovy/src/test/java/org/apache/camel/language/groovy/GroovyExpressionTest.java
 
b/components/camel-groovy/src/test/java/org/apache/camel/language/groovy/GroovyExpressionTest.java
index 9a01173e65b..946d1b90fec 100644
--- 
a/components/camel-groovy/src/test/java/org/apache/camel/language/groovy/GroovyExpressionTest.java
+++ 
b/components/camel-groovy/src/test/java/org/apache/camel/language/groovy/GroovyExpressionTest.java
@@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
 import static org.apache.camel.test.junit5.TestSupport.assertExpression;
 import static org.apache.camel.test.junit5.TestSupport.assertInMessageHeader;
 import static org.apache.camel.test.junit5.TestSupport.assertPredicate;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
@@ -68,6 +69,18 @@ public class GroovyExpressionTest {
         assertPredicate(GroovyLanguage.groovy("variables['cheese'] == 
'gauda'"), exchange, true);
     }
 
+    @Test
+    public void testVariableHeaders() {
+        exchange.removeVariable("cheese");
+        exchange.setVariable("header:myKey.foo", "abc");
+        exchange.setVariable("header:myKey.bar", 123);
+        exchange.setVariable("myOtherKey", "Hello Again");
+
+        assertEquals("Hello Again", 
GroovyLanguage.groovy("variables['myOtherKey']").evaluate(exchange));
+        assertEquals("abc", 
GroovyLanguage.groovy("variables['header:myKey.foo']").evaluate(exchange));
+        assertEquals(123, 
GroovyLanguage.groovy("variables['header:myKey.bar']").evaluate(exchange));
+    }
+
     @Test
     public void testException() {
         Exception e = new IllegalArgumentException("Forced");
diff --git a/core/camel-api/src/main/java/org/apache/camel/Exchange.java 
b/core/camel-api/src/main/java/org/apache/camel/Exchange.java
index ab55b6ac7e7..19a3e34e072 100644
--- a/core/camel-api/src/main/java/org/apache/camel/Exchange.java
+++ b/core/camel-api/src/main/java/org/apache/camel/Exchange.java
@@ -532,9 +532,9 @@ public interface Exchange extends VariableAware {
     Object removeVariable(String name);
 
     /**
-     * Returns the variables from the current exchange
+     * Returns the variables from the current exchange (read-only)
      *
-     * @return the variables from the current exchange in a Map.
+     * @return the variables from the current exchange in a Map (read-only).
      */
     Map<String, Object> getVariables();
 
diff --git a/core/camel-api/src/main/java/org/apache/camel/Variables.java 
b/core/camel-api/src/main/java/org/apache/camel/Variables.java
index 30e9ccfd7f2..9feeb2830ab 100644
--- a/core/camel-api/src/main/java/org/apache/camel/Variables.java
+++ b/core/camel-api/src/main/java/org/apache/camel/Variables.java
@@ -23,7 +23,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Marks a parameter as being an injection point of the variables
+ * Marks a parameter as being an injection point of the variables (read-only)
  *
  * @see Exchange#getVariables()
  */
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java
index 8245be4b409..c203450e75c 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanWithVariablesAndBodyInject3Test.java
@@ -26,48 +26,29 @@ import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.spi.Registry;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
 public class BeanWithVariablesAndBodyInject3Test extends ContextTestSupport {
+
     private final MyBean myBean = new MyBean();
 
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
             public void configure() {
-                
from("direct:start").to("bean:myBean?method=doSomething").to("mock:finish");
+                from("direct:start")
+                        .setVariable("cheese", constant("gauda"))
+                        
.to("bean:myBean?method=doSomething").to("mock:finish");
             }
         };
     }
 
     @Test
-    public void testInOnly() throws Exception {
+    public void testVariables() throws Exception {
         MockEndpoint end = getMockEndpoint("mock:finish");
-        end.expectedBodiesReceived("Hello!");
+        end.expectedBodiesReceived("Hello 1");
 
         sendBody("direct:start", "Test Input");
 
         assertMockEndpointsSatisfied();
-
-        assertNotNull(end.getExchanges().get(0).getIn().getBody());
-        assertEquals("Hello!", end.getExchanges().get(0).getIn().getBody());
-    }
-
-    @Test
-    public void testInOut() throws Exception {
-        MockEndpoint end = getMockEndpoint("mock:finish");
-        end.expectedBodiesReceived("Hello!");
-        end.expectedVariableReceived("out", 123);
-
-        String out = template.requestBody("direct:start", "Test Input", 
String.class);
-        assertEquals("Hello!", out);
-
-        assertMockEndpointsSatisfied();
-
-        assertNotNull(end.getExchanges().get(0).getIn().getBody());
-        assertEquals("Hello!", end.getExchanges().get(0).getIn().getBody());
-        assertEquals(123, end.getExchanges().get(0).getVariable("out"));
     }
 
     @Override
@@ -80,8 +61,7 @@ public class BeanWithVariablesAndBodyInject3Test extends 
ContextTestSupport {
     public static class MyBean {
 
         public String doSomething(@Body String body, @Variables Map<String, 
Object> variables) {
-            variables.put("out", 123);
-            return "Hello!";
+            return "Hello " + variables.size();
         }
     }
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/VariableTest.java 
b/core/camel-core/src/test/java/org/apache/camel/language/VariableTest.java
index 41f6654c8d5..9998653af15 100644
--- a/core/camel-core/src/test/java/org/apache/camel/language/VariableTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/language/VariableTest.java
@@ -46,6 +46,7 @@ public class VariableTest extends LanguageTestSupport {
 
     @Test
     public void testVariableHeaders() {
+        exchange.removeVariable("cheese");
         exchange.setVariable("header:myKey.foo", "abc");
         exchange.setVariable("header:myKey.bar", 123);
         exchange.setVariable("myOtherKey", "Hello Again");
@@ -58,6 +59,13 @@ public class VariableTest extends LanguageTestSupport {
         assertEquals(2, map.size());
         assertEquals("abc", map.get("foo"));
         assertEquals(123, map.get("bar"));
+
+        // getVariables should also include the headers
+        map = exchange.getVariables();
+        assertEquals(3, map.size());
+        assertEquals("Hello Again", map.get("myOtherKey"));
+        assertEquals("abc", map.get("header:myKey.foo"));
+        assertEquals(123, map.get("header:myKey.bar"));
     }
 
     @Test
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
index c6a2d27650a..aed165d3392 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
@@ -946,7 +946,7 @@ public class SimpleTest extends LanguageTestSupport {
 
     @Test
     public void testVariables() {
-        exchange.getVariables().putAll(exchange.getMessage().getHeaders());
+        exchange.getMessage().getHeaders().forEach(exchange::setVariable);
         exchange.getMessage().removeHeaders("*");
 
         Map<String, Object> variables = exchange.getVariables();
@@ -991,11 +991,11 @@ public class SimpleTest extends LanguageTestSupport {
 
     @Test
     public void testVariableKeyWithSpace() {
-        exchange.getVariables().putAll(exchange.getMessage().getHeaders());
+        exchange.getMessage().getHeaders().forEach(exchange::setVariable);
         exchange.getMessage().removeHeaders("*");
 
         Map<String, Object> variables = exchange.getVariables();
-        variables.put("some key", "Some Value");
+        exchange.setVariable("some key", "Some Value");
         assertEquals(4, variables.size());
 
         assertExpression("${variableAs(foo,String)}", "abc");
@@ -1015,7 +1015,7 @@ public class SimpleTest extends LanguageTestSupport {
 
     @Test
     public void testVariableAs() {
-        exchange.getVariables().putAll(exchange.getMessage().getHeaders());
+        exchange.getMessage().getHeaders().forEach(exchange::setVariable);
         exchange.getMessage().removeHeaders("*");
 
         assertExpression("${variableAs(foo,String)}", "abc");
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/util/ExchangeHelperTest.java 
b/core/camel-core/src/test/java/org/apache/camel/util/ExchangeHelperTest.java
index 564049ac924..575982b3774 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/util/ExchangeHelperTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/util/ExchangeHelperTest.java
@@ -158,8 +158,10 @@ public class ExchangeHelperTest extends ContextTestSupport 
{
         assertSame(exchange.getMessage(), map.get("response"));
         assertSame(exchange.getIn().getHeaders(), map.get("headers"));
         assertSame(exchange.getIn().getHeaders(), map.get("header"));
-        assertSame(exchange.getVariables(), map.get("variable"));
-        assertSame(exchange.getVariables(), map.get("variables"));
+        Map vars = (Map) map.get("variable");
+        assertEquals(exchange.getVariables().size(), vars.size());
+        vars = (Map) map.get("variables");
+        assertEquals(exchange.getVariables().size(), vars.size());
         assertSame(exchange.getIn().getBody(), map.get("body"));
         assertSame(exchange.getContext(), map.get("camelContext"));
     }
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java 
b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java
index c8fcc9e3f96..106c1b14c03 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java
@@ -376,7 +376,7 @@ public final class ExchangeHelper {
             result.getProperties().putAll(source.getProperties());
         }
         if (source.hasVariables()) {
-            result.getVariables().putAll(source.getVariables());
+            source.getVariables().forEach(result::setVariable);
         }
 
         final ExchangeExtension sourceExtension = 
source.getExchangeExtension();
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeVariableRepository.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeVariableRepository.java
index 0e144ce3627..0c7be28ac71 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeVariableRepository.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeVariableRepository.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.support;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -44,6 +46,27 @@ final class ExchangeVariableRepository extends 
AbstractVariableRepository {
         this.headers.putAll(source.headers);
     }
 
+    @Override
+    public Map<String, Object> getVariables() {
+        Map<String, Object> answer;
+        if (headers.isEmpty()) {
+            answer = super.getVariables();
+        } else {
+            answer = new HashMap<>(super.getVariables());
+            // flatten headers
+            headers.forEach((k, v) -> {
+                answer.put("header:" + k, v);
+            });
+        }
+        return Collections.unmodifiableMap(answer);
+    }
+
+    @Override
+    public void setVariables(Map<String, Object> map) {
+        super.setVariables(map);
+        this.headers.clear();
+    }
+
     @Override
     public Object getVariable(String name) {
         String id = StringHelper.before(name, ":");
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_10.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_10.adoc
index 9fa09efecfd..282845bfe91 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_10.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_10.adoc
@@ -59,6 +59,8 @@ not be able to add the `otherwise` block to the outer Choice.
 
 === Propagating variables in EIPs in seda/kamelet components
 
+The `Exchange.getVariables()` now return a read-only map. Use the other APIs 
put/remove variables from the Exchange.
+
 The kamelet and seda component and EIPs such as Split, Multicast, Recipient 
List, Enrich, PollEnrich, Loop (copy mode)
 will now also propagate exchange variables as well into the result (i.e. 
exchange properties and message headers is already being propagated).
 
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_12.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_12.adoc
index 912e783feb1..128b73390d6 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_12.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_12.adoc
@@ -21,6 +21,8 @@ The package scan classes has moved from `camel-base-engine` 
to `camel-support` J
 
 The `ExchangeHelper.copyResults` has been improved to also copy over exchange 
variables from the source to the target.
 
+The `Exchange.getVariables()` now return a read-only map. Use the other APIs 
put/remove variables from the Exchange.
+
 ==== Propagating variables in EIPs in seda/kamelet components
 
 The kamelet and seda component and EIPs such as Split, Multicast, Recipient 
List, Enrich, PollEnrich, Loop (copy mode)

Reply via email to