This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch camel-22884-when-method-validation in repository https://gitbox.apache.org/repos/asf/camel.git
commit 5d1bc14daa89e6a12c59c11c9ced2ce6ced67101 Author: Guillaume Nodet <[email protected]> AuthorDate: Fri Mar 13 08:36:13 2026 +0100 CAMEL-22884: Validate method attribute placement in when clause Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../camel/model/BasicOutputExpressionNode.java | 28 +++++++++++++ .../org/apache/camel/xml/in/ModelParserTest.java | 46 ++++++++++++++++++++++ 2 files changed, 74 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..679edbff0924 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 @@ -449,6 +449,52 @@ 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(); + }); + assertTrue(e.getMessage().contains("already has a predicate") + || e.getCause().getMessage().contains("already has a predicate"), + "Error message should indicate that the when clause already has a predicate: " + e.getMessage()); + } + + @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";
