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)