Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -983,6 +983,22 @@ private MethodInfo chooseBestPossibleMethodInfo(
return null;
}

/**
* Whether a method of this name is never a candidate for Camel Bean Binding, such as equals and the other methods
* of java.lang.Object. getClass is one too, but an OGNL call of it is invoked on its own.
*
* @param name the name of the method
* @return true if the name is excluded from Camel Bean Binding
*/
public static boolean isExcludedMethodName(String name) {
for (String s : EXCLUDED_METHOD_NAMES) {
if (s.equals(name)) {
return true;
}
}
return false;
}

/**
* Validates whether the given method is a valid candidate for Camel Bean Binding.
*
Expand All @@ -993,10 +1009,8 @@ private MethodInfo chooseBestPossibleMethodInfo(
protected boolean isValidMethod(Class<?> clazz, Method method) {
// method name must not be in the excluded list
String name = method.getName();
for (String s : EXCLUDED_METHOD_NAMES) {
if (name.equals(s)) {
return false;
}
if (isExcludedMethodName(name)) {
return false;
}

// special for Object where clone is not allowed to be called directly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,24 @@ private static String methodHint(String methodName, Throwable e) {
return methodName;
}

/**
* Why ${body.equals('x')}, ${body.hashCode()} and the other methods Camel does not call on a bean fail: the body is
* not the reason, so the hint says what to write instead of what the body is (CAMEL-26041). Null for another
* method.
*/
private static String excludedMethodHint(String methodName) {
String name = methodName != null ? StringHelper.before(methodName, "(", methodName).trim() : null;
// getClass is excluded from the bean binding, but BeanInfo invokes it on its own
if (name == null || "getClass".equals(name) || !BeanInfo.isExcludedMethodName(name)) {
return null;
}
if ("equals".equals(name)) {
return " (Camel does not call equals on a bean: compare with an operator instead, such as ${body} == 'value'"
+ " in simple)";
}
return " (Camel does not call " + name + " on a bean)";
}

/**
* The bean name, or for an OGNL on the message body (${body.foo()}) what the body is, so the message does not say
* "on null".
Expand Down Expand Up @@ -543,6 +561,13 @@ private Object invokeMethodIfPresent(
return value;
}
String method = methodHint(methodName, resultExchange.getException());
String excluded = excludedMethodHint(methodName);
if (excluded != null) {
// ${body.equals('x')}: no bean binding calls it, whatever the body is (CAMEL-26041)
throw new RuntimeBeanExpressionException(
exchange, describeBean(holder, beanName, exchange), method + excluded,
resultExchange.getException());
}
Object bean = beanOf(holder, exchange);
String body = bodyHint(exchange, bean);
String list = body == null ? listHint(bean, methodName) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,29 @@ public void testOgnlSizeOnAnIteratorSaysItHasNone() {
.contains("it has no size and can be read once: split it, or have the producer give a List");
}

@Test
public void testEqualsOnTheBodySaysHowToCompare() {
// CAMEL-26041: Camel does not call equals on a bean, so the text of the body is not why it fails
exchange.getIn().setBody("test-value-2");
Exception e = assertThrows(Exception.class,
() -> context.resolveLanguage("simple").createExpression("${body.equals('test-value-2')}")
.evaluate(exchange, String.class));
assertThat(e.getMessage()).contains("equals('test-value-2') (Camel does not call equals on a bean: compare with an"
+ " operator instead, such as ${body} == 'value' in simple)")
.doesNotContain("unmarshal");
}

@Test
public void testHashCodeOnAListIsNotAMissingElement() {
// CAMEL-26041: nor is the body a List without such a method or key
exchange.getIn().setBody(List.of("A1", "A2"));
Exception e = assertThrows(Exception.class,
() -> context.resolveLanguage("simple").createExpression("${body.hashCode()}").evaluate(exchange,
String.class));
assertThat(e.getMessage()).contains("hashCode() (Camel does not call hashCode on a bean)")
.doesNotContain("a List has no method");
}

@Test
public void testKeyOnTheFileAsReadSaysToUnmarshal() {
// CAMEL-25749: ${body[status]} on the file consumer's body, before any unmarshal
Expand Down
Loading