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 73854db8f2bd CAMEL-24376: Allow boolean-zen operands in Simple logical 
expressions
73854db8f2bd is described below

commit 73854db8f2bddf6777263ad7da4ee849e5a23c7b
Author: Omar Atie <[email protected]>
AuthorDate: Wed Aug 12 00:39:19 2026 -0700

    CAMEL-24376: Allow boolean-zen operands in Simple logical expressions
    
    Fix SimpleIllegalSyntaxException when boolean-zen shorthand (standalone
    ${header.foo} or ${exchangeProperty.foo}) is used as an operand of ||
    or &&. Accept SimpleFunctionStart as a valid logical operand and wrap it
    with matchesValue() in csimple codegen for correct boolean evaluation.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 .../camel/language/csimple/CSimpleHelper.java      |   4 +
 .../language/simple/ast/LogicalExpression.java     |  30 +++++-
 .../csimple/CSimplePredicateParserTest.java        |   9 ++
 .../simple/SimplePredicateParserLogicalTest.java   | 108 ++++++++++++++++-----
 4 files changed, 125 insertions(+), 26 deletions(-)

diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
index 21fc2018c579..877841580665 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
@@ -1310,6 +1310,10 @@ public final class CSimpleHelper {
         return null;
     }
 
+    public static boolean matchesValue(Exchange exchange, Object value) {
+        return ObjectHelper.evaluateValuePredicate(value);
+    }
+
     public static boolean isNot(Exchange exchange, Object value) {
         if (value == null) {
             return true;
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/LogicalExpression.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/LogicalExpression.java
index 535dce4fbfa8..bb7f69a016a4 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/LogicalExpression.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/LogicalExpression.java
@@ -48,7 +48,7 @@ public class LogicalExpression extends BaseSimpleNode {
     }
 
     public boolean acceptLeftNode(SimpleNode lef) {
-        if (!(lef instanceof BinaryExpression) && !(lef instanceof 
LogicalExpression)) {
+        if (!isValidPredicateOperand(lef)) {
             return false;
         }
         this.left = lef;
@@ -56,13 +56,24 @@ public class LogicalExpression extends BaseSimpleNode {
     }
 
     public boolean acceptRightNode(SimpleNode right) {
-        if (!(right instanceof BinaryExpression) && !(right instanceof 
LogicalExpression)) {
+        if (!isValidPredicateOperand(right)) {
             return false;
         }
         this.right = right;
         return true;
     }
 
+    /**
+     * Predicate operands for logical AND/OR include binary/logical 
expressions as well as boolean-zen shorthand
+     * (standalone functions such as {@code ${header.active}} or {@code 
${exchangeProperty.flag}}) that are evaluated
+     * via {@link org.apache.camel.support.ExpressionToPredicateAdapter}.
+     */
+    private static boolean isValidPredicateOperand(SimpleNode node) {
+        return node instanceof BinaryExpression
+                || node instanceof LogicalExpression
+                || node instanceof SimpleFunctionStart;
+    }
+
     public LogicalOperatorType getOperator() {
         return operator;
     }
@@ -137,8 +148,8 @@ public class LogicalExpression extends BaseSimpleNode {
         ObjectHelper.notNull(left, "left node", this);
         ObjectHelper.notNull(right, "right node", this);
 
-        final String leftExp = left.createCode(camelContext, expression);
-        final String rightExp = right.createCode(camelContext, expression);
+        final String leftExp = predicateOperandCode(left, camelContext, 
expression);
+        final String rightExp = predicateOperandCode(right, camelContext, 
expression);
 
         if (operator == LogicalOperatorType.AND) {
             return leftExp + " && " + rightExp;
@@ -148,4 +159,15 @@ public class LogicalExpression extends BaseSimpleNode {
 
         throw new SimpleParserException("Unknown logical operator " + 
operator, token.getIndex());
     }
+
+    private static String predicateOperandCode(SimpleNode node, CamelContext 
camelContext, String expression)
+            throws SimpleParserException {
+        String code = node.createCode(camelContext, expression);
+        code = code.replace(BaseSimpleParser.CODE_START, "");
+        code = code.replace(BaseSimpleParser.CODE_END, "");
+        if (node instanceof SimpleFunctionStart) {
+            return "matchesValue(exchange, " + code + ")";
+        }
+        return code;
+    }
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/csimple/CSimplePredicateParserTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/csimple/CSimplePredicateParserTest.java
index 4e9d3e1ac204..56e4f8f1fa20 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/language/csimple/CSimplePredicateParserTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/csimple/CSimplePredicateParserTest.java
@@ -103,4 +103,13 @@ public class CSimplePredicateParserTest {
                 "isNotEqualTo(exchange, exchangePropertyAs(exchange, \"foo\", 
com.foo.User.class).getName(), \"bar\")", code);
     }
 
+    @Test
+    public void testParseBooleanZenLogicalOr() {
+        CSimplePredicateParser parser = new CSimplePredicateParser();
+        String code = parser.parsePredicate("${header.token} == null || 
${exchangeProperty.forceNewSessionToken}");
+        Assertions.assertEquals(
+                "isEqualTo(exchange, header(message, \"token\"), null) || 
matchesValue(exchange, exchangeProperty(exchange, \"forceNewSessionToken\"))",
+                code);
+    }
+
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimplePredicateParserLogicalTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimplePredicateParserLogicalTest.java
index bd62f2cb1089..f7e630c301cc 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimplePredicateParserLogicalTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimplePredicateParserLogicalTest.java
@@ -21,18 +21,17 @@ import org.apache.camel.Predicate;
 import org.apache.camel.language.simple.types.SimpleIllegalSyntaxException;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Regression tests for prepareLogicalExpressions in SimplePredicateParser. 
Covers the bug where the right-hand token
  * was reported as the left-hand token in the "does not support right hand 
side token" error message.
  */
-public class SimplePredicateParserLogicalTest extends ExchangeTestSupport {
+class SimplePredicateParserLogicalTest extends ExchangeTestSupport {
 
     @Test
-    public void testAndWithFunctionRightHandSide() {
+    void testAndWithFunctionRightHandSide() {
         exchange.getIn().setBody("hello");
         exchange.getIn().setHeader("active", true);
 
@@ -41,11 +40,78 @@ public class SimplePredicateParserLogicalTest extends 
ExchangeTestSupport {
         Predicate predicate = parser.parsePredicate();
         predicate.init(context);
 
-        assertTrue(predicate.matches(exchange));
+        assertThat(predicate.matches(exchange)).isTrue();
     }
 
     @Test
-    public void testAndWithLiteralRightHandSide() {
+    void testOrWithBooleanZenRightHandSide() {
+        // CAMEL-24376: boolean-zen shorthand must work as the right operand 
of ||
+        exchange.getIn().setHeader("token", null);
+        exchange.setProperty("forceNewSessionToken", true);
+
+        SimplePredicateParser parser = new SimplePredicateParser(
+                context, "${header.token} == null || 
${exchangeProperty.forceNewSessionToken}", true, null);
+        Predicate predicate = parser.parsePredicate();
+        predicate.init(context);
+
+        assertThat(predicate.matches(exchange)).isTrue();
+    }
+
+    @Test
+    void testOrWithBooleanZenLeftHandSide() {
+        exchange.getIn().setHeader("active", true);
+        exchange.getIn().setBody("other");
+
+        SimplePredicateParser parser = new SimplePredicateParser(
+                context, "${header.active} || ${body} == 'hello'", true, null);
+        Predicate predicate = parser.parsePredicate();
+        predicate.init(context);
+
+        assertThat(predicate.matches(exchange)).isTrue();
+    }
+
+    @Test
+    void testAndWithBooleanZenOperands() {
+        exchange.getIn().setHeader("enabled", true);
+        exchange.setProperty("ready", true);
+
+        SimplePredicateParser parser = new SimplePredicateParser(
+                context, "${header.enabled} && ${exchangeProperty.ready}", 
true, null);
+        Predicate predicate = parser.parsePredicate();
+        predicate.init(context);
+
+        assertThat(predicate.matches(exchange)).isTrue();
+
+        exchange.setProperty("ready", false);
+        assertThat(predicate.matches(exchange)).isFalse();
+    }
+
+    @Test
+    void testOrWithBooleanZenFalseWhenBothOperandsFalse() {
+        exchange.getIn().setHeader("token", "abc");
+        exchange.setProperty("forceNewSessionToken", false);
+
+        SimplePredicateParser parser = new SimplePredicateParser(
+                context, "${header.token} == null || 
${exchangeProperty.forceNewSessionToken}", true, null);
+        Predicate predicate = parser.parsePredicate();
+        predicate.init(context);
+
+        assertThat(predicate.matches(exchange)).isFalse();
+    }
+
+    @Test
+    void testStandaloneBooleanZenStillWorks() {
+        exchange.getIn().setHeader("foo", "yes");
+
+        SimplePredicateParser parser = new SimplePredicateParser(context, 
"${header.foo}", true, null);
+        Predicate predicate = parser.parsePredicate();
+        predicate.init(context);
+
+        assertThat(predicate.matches(exchange)).isTrue();
+    }
+
+    @Test
+    void testAndWithLiteralRightHandSide() {
         exchange.getIn().setBody("foo");
 
         SimplePredicateParser parser = new SimplePredicateParser(
@@ -53,11 +119,11 @@ public class SimplePredicateParserLogicalTest extends 
ExchangeTestSupport {
         Predicate predicate = parser.parsePredicate();
         predicate.init(context);
 
-        assertTrue(predicate.matches(exchange));
+        assertThat(predicate.matches(exchange)).isTrue();
     }
 
     @Test
-    public void testOrWithFunctionRightHandSide() {
+    void testOrWithFunctionRightHandSide() {
         exchange.getIn().setBody("hello");
         exchange.getIn().setHeader("score", 5);
 
@@ -66,11 +132,11 @@ public class SimplePredicateParserLogicalTest extends 
ExchangeTestSupport {
         Predicate predicate = parser.parsePredicate();
         predicate.init(context);
 
-        assertTrue(predicate.matches(exchange));
+        assertThat(predicate.matches(exchange)).isTrue();
     }
 
     @Test
-    public void testOrAllFalse() {
+    void testOrAllFalse() {
         exchange.getIn().setBody("hello");
         exchange.getIn().setHeader("score", 1);
 
@@ -79,11 +145,11 @@ public class SimplePredicateParserLogicalTest extends 
ExchangeTestSupport {
         Predicate predicate = parser.parsePredicate();
         predicate.init(context);
 
-        assertFalse(predicate.matches(exchange));
+        assertThat(predicate.matches(exchange)).isFalse();
     }
 
     @Test
-    public void testAndWithNumericRightHandSide() {
+    void testAndWithNumericRightHandSide() {
         exchange.getIn().setBody(42);
 
         SimplePredicateParser parser = new SimplePredicateParser(
@@ -91,11 +157,11 @@ public class SimplePredicateParserLogicalTest extends 
ExchangeTestSupport {
         Predicate predicate = parser.parsePredicate();
         predicate.init(context);
 
-        assertTrue(predicate.matches(exchange));
+        assertThat(predicate.matches(exchange)).isTrue();
     }
 
     @Test
-    public void testAndWithNullRightHandSide() {
+    void testAndWithNullRightHandSide() {
         exchange.getIn().setBody("present");
         exchange.getIn().setHeader("tag", "x");
 
@@ -104,11 +170,11 @@ public class SimplePredicateParserLogicalTest extends 
ExchangeTestSupport {
         Predicate predicate = parser.parsePredicate();
         predicate.init(context);
 
-        assertTrue(predicate.matches(exchange));
+        assertThat(predicate.matches(exchange)).isTrue();
     }
 
     @Test
-    public void testChainedAndOrLogicalOperators() {
+    void testChainedAndOrLogicalOperators() {
         exchange.getIn().setBody("alpha");
         exchange.getIn().setHeader("flag", true);
 
@@ -117,20 +183,18 @@ public class SimplePredicateParserLogicalTest extends 
ExchangeTestSupport {
         Predicate predicate = parser.parsePredicate();
         predicate.init(context);
 
-        assertTrue(predicate.matches(exchange));
+        assertThat(predicate.matches(exchange)).isTrue();
     }
 
     @Test
-    public void testInvalidRightHandSideReportsRightToken() {
+    void testInvalidRightHandSideReportsRightToken() {
         // "&&" followed by a bare numeric (not a binary expression) is 
invalid syntax.
         // The error message must say "right hand side token 42" (the actual 
offending token),
         // not "right hand side token ==" (which would indicate the left-hand 
node was reported).
         SimplePredicateParser parser = new SimplePredicateParser(
                 context, "${body} == 'foo' && 42", true, null);
         SimpleIllegalSyntaxException ex = 
assertThrows(SimpleIllegalSyntaxException.class, parser::parsePredicate);
-        assertTrue(ex.getMessage().contains("right hand side token 42"),
-                "Error message should say 'right hand side token 42', but was: 
" + ex.getMessage());
-        assertFalse(ex.getMessage().contains("right hand side token =="),
-                "Error message must not say 'right hand side token ==', but 
was: " + ex.getMessage());
+        assertThat(ex.getMessage()).contains("right hand side token 42");
+        assertThat(ex.getMessage()).doesNotContain("right hand side token ==");
     }
 }

Reply via email to