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 d35571d23f19 CAMEL-26041: camel-bean - a call of equals on the body
says how to compare, not to unmarshal the body (#28315)
d35571d23f19 is described below
commit d35571d23f19ec84b46db83c6689a892fff6e35d
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Oct 23 10:44:52 2026 +0200
CAMEL-26041: camel-bean - a call of equals on the body says how to compare,
not to unmarshal the body (#28315)
Camel never calls the java.lang.Object methods on a bean, so
${body.equals('x')} fails whatever the body is, but since CAMEL-25749 the error
advised unmarshalling the body. For an excluded method name the hint now says
how to compare instead.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
.../org/apache/camel/component/bean/BeanInfo.java | 22 +++++++++++++++----
.../apache/camel/language/bean/BeanExpression.java | 25 ++++++++++++++++++++++
.../language/simple/SimpleSyntaxHintsTest.java | 23 ++++++++++++++++++++
3 files changed, 66 insertions(+), 4 deletions(-)
diff --git
a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
index 13a0ae2a22e7..3bb635ab6d69 100644
---
a/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
+++
b/components/camel-bean/src/main/java/org/apache/camel/component/bean/BeanInfo.java
@@ -983,6 +983,22 @@ public class BeanInfo {
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.
*
@@ -993,10 +1009,8 @@ public class BeanInfo {
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
diff --git
a/components/camel-bean/src/main/java/org/apache/camel/language/bean/BeanExpression.java
b/components/camel-bean/src/main/java/org/apache/camel/language/bean/BeanExpression.java
index 1a5e368d6f26..c81504b037c9 100644
---
a/components/camel-bean/src/main/java/org/apache/camel/language/bean/BeanExpression.java
+++
b/components/camel-bean/src/main/java/org/apache/camel/language/bean/BeanExpression.java
@@ -415,6 +415,24 @@ public class BeanExpression implements Expression,
Predicate {
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".
@@ -543,6 +561,13 @@ public class BeanExpression implements Expression,
Predicate {
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;
diff --git
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleSyntaxHintsTest.java
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleSyntaxHintsTest.java
index fcc8ac4567aa..9e9946b61c4e 100644
---
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleSyntaxHintsTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleSyntaxHintsTest.java
@@ -220,6 +220,29 @@ public class SimpleSyntaxHintsTest extends
ExchangeTestSupport {
.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