Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,32 @@ public void setOutputs(List<ProcessorDefinition<?>> outputs) {
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,52 @@ public void testParseError() throws Exception {
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>";
Comment thread
gnodet marked this conversation as resolved.
Outdated
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());
Comment on lines +497 to +498
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using AssertJ assertions will allow to write it in a single assertion and have a more precise error message out of the box

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — replaced with assertThat(e).hasStackTraceContaining("already has a predicate") in 577b5cb.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment was for another piece of code

}

private Path getResourceFolder() {
final URL resource = getClass().getClassLoader().getResource("barInterceptorRoute.xml");
assert resource != null : "Cannot find barInterceptorRoute.xml";
Expand Down
Loading