shashank created CAMEL-26329:
--------------------------------
Summary: camel-support - Simple == compares a number and a numeric
String as text when they are written differently: ${header.amount} == '10' is
false for a BigDecimal 10.00 while <= and >= are true
Key: CAMEL-26329
URL: https://issues.apache.org/jira/browse/CAMEL-26329
Project: Camel
Issue Type: Bug
Components: camel-core
Reporter: shashank
Assignee: shashank
Since CAMEL-25013 (4.23.0) the Simple comparison operators compare two numbers,
or a number and a numeric String, by their values, and the 4.23 upgrade guide
entry lists "a number compared with a numeric {{String}}" among them (its
examples include {{==}}). {{ObjectHelper.typeCoerceCompare}} does that, but
{{typeCoerceEquals}} only got the number/number case. For a number and a
numeric String that are not written the same way, {{==}} still converts the
String to the type of the number and uses {{equals}} ({{BigDecimal.equals}}
also compares the scale), or converts the number to a String and compares the
text. So {{==}} and {{!=}} disagree with {{<=}} and {{>=}} (main aa63c0a4cb94):
{code}
amount = BigDecimal 10.00 (for example a DECIMAL(10,2) column read with
camel-sql)
${header.amount} <= '10' true
${header.amount} >= '10' true
${header.amount} == '10' false
${header.amount} == ${header.s} false, for a String header s = "10"
text = String "10.00"
${header.text} == 10 false (<= and >= are true)
count = Integer 3
${header.count} == '3.0' false
${header.count} in '3.0' true (in compares the values since CAMEL-25013)
{code}
The {{==}} result is the same in older versions; since 4.23 it disagrees with
the other operators, which compare the values.
{{simple-operators.adoc}} shows {{simple("$\{header.bar} == '100'")}} as the
way to compare a header with a number, so a {{choice()}} on a BigDecimal amount
with a scale takes the wrong branch without an error. The same happens for
{{Integer}}, {{Long}}, {{Short}} and {{BigInteger}} values compared with
{{'1e1'}} or {{' 10'}} (with spaces). A {{Double}} or {{Float}} is not
affected, because the String is converted to a double first.
*Fix* (proposed): in {{typeCoerceEquals}}, when one side is a number other than
a double or float and the other side is a String that parses as a
{{BigDecimal}} (ignoring leading and trailing spaces, as the {{in}} operator
does), compare them with the same {{compareNumbers}} that {{typeCoerceCompare}}
uses. {{typeCoerceCompare}} parses the String the same way, so {{<}} and {{>}}
with {{" 9007199254740992"}} or {{1e0}} are exact and no longer compared as
doubles. The text is checked to have the form of a number before it is parsed
(so text such as {{-}} or {{2026-10-26}} is not handed to the BigDecimal
parser), and text longer than 1000 characters is not parsed: parsing a
BigDecimal takes time that grows with the square of the number of digits (a
million digits take about 12 s). Text that is not a number, null, two Strings,
and doubles are unchanged. A 4.24 upgrade guide entry describes the change, as
{{==}} and {{!=}} give different results than in 4.23 for these values (also
{{=~}}, {{contains}} on a collection, and the Java DSL and mock predicates).
*Tests*: {{TypeCoerceCompareTest}} (4 new methods) and
{{SimpleOperatorTest.testEqualsNumberWithNumericTextWrittenDifferently}} fail
on main and pass with the change. A differential fuzz harness of the Simple
numeric operators (5 million inputs, typed headers vs quoted, unquoted and
header right sides, compared with the comparison of the values) found 1,829
wrong results on main, all {{==}}/{{!=}} of a number and a numeric String
written differently; with the change there are none, and no other input changes
its result.
*How it was found*: a fuzz harness that checks the Simple comparison operators
against each other ({{==}} must agree with {{<=}} and {{>=}} both being true)
on 5 million generated number and text pairs, run on HotSpot; all 1 829
disagreements came from this one cause, and none remains with the fix.
*Affected*: 4.23.0 and main. The fix builds on the value comparison of
CAMEL-25013, which the older branches do not have, so this follow-up is for
main only.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)