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 a8ad07ae0286 CAMEL-25033: camel-bean - pass a parameter value from 
${body} or ${header.x} in the method name as-is (#26908)
a8ad07ae0286 is described below

commit a8ad07ae0286c9f3d3fa02b0616138f841f94e39
Author: allthingssecurity <[email protected]>
AuthorDate: Mon Sep 28 13:32:42 2026 +0530

    CAMEL-25033: camel-bean - pass a parameter value from ${body} or 
${header.x} in the method name as-is (#26908)
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../apache/camel/component/bean/MethodInfo.java    |  20 ++--
 .../bean/BeanParameterValueFromExpressionTest.java | 107 +++++++++++++++++++++
 .../modules/ROOT/pages/bean-binding.adoc           |   5 +
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |  11 +++
 4 files changed, 137 insertions(+), 6 deletions(-)

diff --git 
a/components/camel-bean/src/main/java/org/apache/camel/component/bean/MethodInfo.java
 
b/components/camel-bean/src/main/java/org/apache/camel/component/bean/MethodInfo.java
index a3aac1320046..4f5e31a6731c 100644
--- 
a/components/camel-bean/src/main/java/org/apache/camel/component/bean/MethodInfo.java
+++ 
b/components/camel-bean/src/main/java/org/apache/camel/component/bean/MethodInfo.java
@@ -723,12 +723,24 @@ public class MethodInfo {
                 return null;
             }
 
+            // an explicit null parameter value
+            if ("null".equals(exp)) {
+                return Void.TYPE;
+            }
+
             parameterValue = evaluateSimpleExpression(exchange, index, exp);
 
-            if ("null".equals(parameterValue)) {
+            // the expression evaluated to null, which is a valid value we 
need to honor
+            if (parameterValue == null) {
                 return Void.TYPE;
             }
 
+            // we need to unquote a quoted String parameter value, as the 
enclosing quotes is there to denote a
+            // parameter value, but a value from an expression such as ${body} 
or ${header.foo} is used as-is
+            if (StringHelper.isQuoted(exp.trim()) && parameterValue instanceof 
String string) {
+                parameterValue = 
StringHelper.removeLeadingAndEndingQuotes(string);
+            }
+
             boolean valid = isValidParameterValue(exchange, exp, 
parameterValue, parameterType, varargs);
             if (!valid) {
                 return null;
@@ -760,8 +772,7 @@ public class MethodInfo {
             Expression expression = null;
             try {
                 expression = 
exchange.getContext().resolveLanguage("simple").createExpression(exp);
-                Object result = expression.evaluate(exchange, Object.class);
-                return result != null ? result : "null";
+                return expression.evaluate(exchange, Object.class);
             } catch (Exception e) {
                 throw new ExpressionEvaluationException(
                         expression, "Cannot create/evaluate simple expression: 
" + exp
@@ -788,9 +799,6 @@ public class MethodInfo {
 
         private Object convertParameterValue(
                 Exchange exchange, int index, Object parameterValue, Class<?> 
parameterType, boolean varargs) {
-            if (parameterValue instanceof String string) {
-                parameterValue = 
StringHelper.removeLeadingAndEndingQuotes(string);
-            }
             if (varargs) {
                 return parameterValue;
             }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanParameterValueFromExpressionTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanParameterValueFromExpressionTest.java
new file mode 100644
index 000000000000..6bfd9a498b7e
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/component/bean/BeanParameterValueFromExpressionTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.component.bean;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.Registry;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * A parameter value in the method name that is a Simple expression, such as 
${body} or ${header.foo}, is passed to the
+ * method as-is. Only the quotes of a quoted literal are removed, and only the 
literal null is a null value.
+ */
+class BeanParameterValueFromExpressionTest extends ContextTestSupport {
+
+    private final MyBean bean = new MyBean();
+
+    @Test
+    void testQuotedHeaderValue() {
+        assertEquals("[\"33a64df5\"]", 
template.requestBodyAndHeader("direct:header", "Hello", "v", "\"33a64df5\""));
+        assertEquals("['abc']", template.requestBodyAndHeader("direct:header", 
"Hello", "v", "'abc'"));
+        assertEquals("[  'x'  ]", 
template.requestBodyAndHeader("direct:header", "Hello", "v", "  'x'  "));
+        assertEquals("['abc']", 
template.requestBodyAndHeader("direct:headerUri", "Hello", "v", "'abc'"));
+    }
+
+    @Test
+    void testQuotedBody() {
+        assertEquals("[\"ACME, Inc.\",\"42\"]", 
template.requestBody("direct:body", "\"ACME, Inc.\",\"42\""));
+        assertEquals("['']", template.requestBody("direct:body", "''"));
+    }
+
+    @Test
+    void testQuotedHeaderValues() {
+        assertEquals("['x'|\"y\"]", template.requestBody("direct:two", 
"Hello"));
+    }
+
+    @Test
+    void testNullText() {
+        // the text null is not the null keyword
+        assertEquals("[null]", template.requestBodyAndHeader("direct:header", 
"Hello", "v", "null"));
+        // but an expression that evaluates to null is still passed as null
+        assertEquals("<null>", template.requestBody("direct:header", "Hello"));
+    }
+
+    @Test
+    void testLiterals() {
+        assertEquals("[abc]", template.requestBodyAndHeader("direct:header", 
"Hello", "v", "abc"));
+        assertEquals("[World]", template.requestBody("direct:single", 
"Hello"));
+        assertEquals("[World]", template.requestBody("direct:double", 
"Hello"));
+        assertEquals("<null>", template.requestBody("direct:null", "Hello"));
+        assertEquals("[null]", template.requestBody("direct:quotedNull", 
"Hello"));
+        assertEquals("[\"abc\"]", 
template.requestBodyAndHeader("direct:quotedHeader", "Hello", "v", "\"abc\""));
+    }
+
+    @Override
+    protected Registry createCamelRegistry() throws Exception {
+        Registry jndi = super.createCamelRegistry();
+        jndi.bind("foo", new MyBean());
+        return jndi;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:header").bean(bean, "echo(${header.v})");
+                
from("direct:headerUri").to("bean:foo?method=echo(${header.v})");
+                from("direct:body").bean(bean, "echo(${body})");
+                from("direct:two").setHeader("a", 
constant("'x'")).setHeader("b", constant("\"y\""))
+                        .bean(bean, "two(${header.a}, ${header.b})");
+                from("direct:single").bean(bean, "echo('World')");
+                from("direct:double").bean(bean, "echo(\"World\")");
+                from("direct:null").bean(bean, "echo(null)");
+                from("direct:quotedNull").bean(bean, "echo('null')");
+                from("direct:quotedHeader").bean(bean, "echo('${header.v}')");
+            }
+        };
+    }
+
+    public static class MyBean {
+
+        public String echo(String s) {
+            return s == null ? "<null>" : "[" + s + "]";
+        }
+
+        public String two(String a, String b) {
+            return "[" + a + "|" + b + "]";
+        }
+    }
+}
diff --git a/docs/user-manual/modules/ROOT/pages/bean-binding.adoc 
b/docs/user-manual/modules/ROOT/pages/bean-binding.adoc
index 1c1c93e83cf1..b69720872de3 100644
--- a/docs/user-manual/modules/ROOT/pages/bean-binding.adoc
+++ b/docs/user-manual/modules/ROOT/pages/bean-binding.adoc
@@ -277,6 +277,11 @@ The syntax of the parameters is using the 
xref:components:languages:simple-langu
 language so we have to use `${ }` placeholders in the body to
 refer to the message body.
 
+The value of a Simple expression such as `$\{body}` or `${header.foo}` is 
passed to the method as-is.
+Quotes in the value are kept, and a value that is the text `null` is passed as 
that text.
+Only a parameter written as a quoted String, such as `'World'`, has its quotes 
removed,
+and only the parameter `null` (without quotes) is a `null` value.
+
 If you want to pass in a `null` value, then you can explicitly define this
 in the method option as shown below:
 
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 7f8a3c26da79..50a590a0a90b 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -985,6 +985,17 @@ an `AGENTS.md` file with guidance for AI coding 
assistants, pointing at the Apac
 The `camel-archetype-api-component` archetype also generates its readme again: 
the file was declared
 in the wrong file set and was therefore silently skipped.
 
+=== camel-bean - parameter values in the method name
+
+A parameter value in the method name that is a Simple expression, such as 
`+bean(MyBean.class, "process(${body})")+`
+or `+to("bean:foo?method=check(${header.ETag})")+`, is now passed to the 
method as-is. Previously, when the value was a
+String that started and ended with the same quote (single or double), the 
quotes were removed, and a value that was the
+text `null` was passed as a Java `null`. For example the `ETag` value 
`"33a64df5"` was passed as `33a64df5`.
+
+Quoted String parameters such as `process('World')` still have their quotes 
removed, and the parameter `null` still
+passes `null`, as before. An expression that evaluates to `null` also still 
passes `null`. If a method relied on the old
+behavior for a value from an expression, then it must remove the quotes, or 
check for the text `null`, itself.
+
 === camel-debezium-oracle (breaking change)
 
 The parameters `logMiningBufferEhcacheRollbacksConfig`, 
`logMiningBufferInfinispanCacheRollbacks` have been removed due to the upgrade 
of Debezium to 3.6.3.Final.

Reply via email to