This is an automated email from the ASF dual-hosted git repository.
gnodet 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 38f2715b3a3d CAMEL-22884: Validate method attribute placement in when
clause (#21969)
38f2715b3a3d is described below
commit 38f2715b3a3d53da174208396f1497e86884a491
Author: Guillaume Nodet <[email protected]>
AuthorDate: Wed Mar 18 15:05:00 2026 +0100
CAMEL-22884: Validate method attribute placement in when clause (#21969)
* CAMEL-22884: Validate method attribute placement in when clause
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* CAMEL-22884: Address review comments - use text blocks and AssertJ
---------
Co-authored-by: Claude Opus 4.6 <[email protected]>
---
.../camel/model/BasicOutputExpressionNode.java | 28 +++++++++++++
.../org/apache/camel/xml/in/ModelParserTest.java | 49 ++++++++++++++++++++++
2 files changed, 77 insertions(+)
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/BasicOutputExpressionNode.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/BasicOutputExpressionNode.java
index 2ab7ecb72732..469905347bd0 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/BasicOutputExpressionNode.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/BasicOutputExpressionNode.java
@@ -75,4 +75,32 @@ public abstract class BasicOutputExpressionNode extends
BasicExpressionNode<Basi
public void addOutput(ProcessorDefinition<?> output) {
this.outputs.add(output);
}
+
+ @Override
+ public void setExpression(ExpressionDefinition expression) {
+ // Detect when an expression element (e.g. <method>) appears after
processing steps
+ // inside a when/filter clause in XML/YAML DSL. This is almost
certainly a user mistake
+ // where they intended to use <bean> (processor) instead of <method>
(expression/predicate).
+ // We skip this check when the existing expression wraps an
ExpressionClause (Java DSL),
+ // because preCreateProcessor() legitimately re-sets the expression
after resolving it.
+ if (expression != null && getExpression() != null &&
!outputs.isEmpty()) {
+ ExpressionDefinition existing = getExpression();
+ boolean isExpressionClause
+ = existing.getExpressionValue() instanceof
org.apache.camel.builder.ExpressionClause
+ || existing.getPredicate() instanceof
org.apache.camel.builder.ExpressionClause;
+ if (!isExpressionClause) {
+ String lang = expression.getLanguage() != null
+ ? expression.getLanguage() :
expression.getClass().getSimpleName();
+ throw new IllegalArgumentException(
+ "The " + getShortName() + " already has a predicate ("
+ existing
+ + ") and " + outputs.size()
+ " output(s). "
+ + "The expression '" + lang
+ + "' is being parsed as an
expression/predicate but appears after processing steps. "
+ + "If you intended to call
a bean method as a processing step, use <bean> instead of <method>. "
+ + "An expression element
must be the first child of <" + getShortName()
+ + ">.");
+ }
+ }
+ super.setExpression(expression);
+ }
}
diff --git
a/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
b/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
index 150e89434e8d..882ec709678b 100644
---
a/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
+++
b/core/camel-xml-io/src/test/java/org/apache/camel/xml/in/ModelParserTest.java
@@ -57,6 +57,7 @@ import org.apache.camel.xml.io.XmlPullParserLocationException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -449,6 +450,54 @@ public class ModelParserTest {
assertTrue(e.getMessage().startsWith("Unexpected attribute '{}ref'"));
}
+ @Test
+ public void testMethodAfterStepsInWhenClauseShouldFail() throws Exception {
+ String routesXml = """
+ <routes xmlns="http://camel.apache.org/schema/xml-io">
+ <route>
+ <from uri="direct:start"/>
+ <choice>
+ <when>
+ <simple>${header.foo} == 'bar'</simple>
+ <log message="Condition met"/>
+ <method ref="someBean" method="processFooBar"/>
+ </when>
+ <otherwise>
+ <to uri="mock:other"/>
+ </otherwise>
+ </choice>
+ </route>
+ </routes>
+ """;
+ Exception e = assertThrows(Exception.class, () -> {
+ new ModelParser(new
StringReader(routesXml)).parseRoutesDefinition();
+ });
+ assertThat(e).hasStackTraceContaining("already has a predicate");
+ }
+
+ @Test
+ public void testMethodAsPredicateInWhenClauseShouldWork() throws Exception
{
+ String routesXml = """
+ <routes xmlns="http://camel.apache.org/schema/xml-io">
+ <route>
+ <from uri="direct:start"/>
+ <choice>
+ <when>
+ <method ref="someBean" method="isFoo"/>
+ <to uri="mock:foo"/>
+ </when>
+ <otherwise>
+ <to uri="mock:other"/>
+ </otherwise>
+ </choice>
+ </route>
+ </routes>
+ """;
+ RoutesDefinition routes = new ModelParser(new
StringReader(routesXml)).parseRoutesDefinition().orElse(null);
+ assertNotNull(routes);
+ assertEquals(1, routes.getRoutes().size());
+ }
+
private Path getResourceFolder() {
final URL resource =
getClass().getClassLoader().getResource("barInterceptorRoute.xml");
assert resource != null : "Cannot find barInterceptorRoute.xml";