allthingssecurity opened a new pull request, #28752:
URL: https://github.com/apache/camel/pull/28752

   # Description
   
   [CAMEL-26329](https://issues.apache.org/jira/browse/CAMEL-26329), a 
follow-up of [CAMEL-25013](https://issues.apache.org/jira/browse/CAMEL-25013) 
(#26873, #26930)
   
   #26873 made `ObjectHelper.typeCoerceCompare` compare a number and a numeric 
`String` by their values, and its 4.23 upgrade guide entry lists "a number 
compared with a numeric `String`" among the comparisons that compare values 
(its examples include `==`). When #26930 did the same for `in`, the review said 
it "makes `in` agree with `==`". But `typeCoerceEquals` only got the 
number/number case. When a number and a numeric `String` are written 
differently, `==` still converted the `String` to the type of the number and 
used `equals` (`BigDecimal.equals` also compares the scale), or compared the 
text. So `==` and `!=` disagreed with `<=`, `>=` and `in`:
   
   ```
   amount = BigDecimal 10.00 (a DECIMAL(10,2) column, for example)
   ${header.amount} <= '10'   true
   ${header.amount} >= '10'   true
   ${header.amount} == '10'   false   (also with a String header "10" on the 
right)
   
   ${header.text} == 10       false for a String "10.00"  (<= and >= are true)
   ${header.count} == '3.0'   false for an Integer 3, while ${header.count} in 
'3.0' is true
   ```
   
   `simple-operators.adoc` shows `${header.bar} == '100'` as the way to compare 
a header with a number, so a `choice()` on a `BigDecimal` amount with a scale 
took the wrong branch, with no error. The `==` result is the same in older 
versions; 4.23 made the other operators compare the values, and its guide entry 
says so.
   
   Changes:
   - `typeCoerceEquals`: a number other than a `Double` or `Float`, and a 
`String` that parses as a `BigDecimal` (leading and trailing spaces ignored, as 
the `in` operator does since #26930), are compared with the same 
`compareNumbers` that `typeCoerceCompare` uses. Both argument orders are 
covered.
   - `typeCoerceCompare` parses the `String` the same way (`asNumber`), so 
`<`/`>` with `" 9007199254740992"` or `"1e0"` compare exact values instead of 
doubles, and agree with `==`. For plain decimal text such as `10.5` nothing 
changes.
   - The text is checked to have the form of a number (sign, digits, decimal 
point, exponent) before it is parsed, so text that is not a number, including 
text such as `-` or `2026-10-26`, is not handed to the `BigDecimal` parser and 
throws no `NumberFormatException` there (the type converter fallback for such 
text is as before).
   - Text longer than 1000 characters is not parsed as a number. Parsing a 
`BigDecimal` takes time that grows with the square of the number of digits: 
with this change and no limit, `5 ==` a decimal `String` of 100,000 digits 
(`111...1.5`) took 129 ms (1 ms on main) and a million digits take about 12 s. 
With the limit, `==` and `<`/`>` with such text take about 1 ms; on main, `<` 
and `>` with a 100,000-digit decimal already took 126 ms.
   - Unchanged: text that is not a number, `null`, two `String` values (the 
numeric comparison of digit strings from CAMEL-24580 stays as is), and 
`Double`/`Float` values, which were already compared with a numeric `String` by 
converting it to a double.
   - Upgrade guide (4.24): a `camel-core` entry. `==` and `!=` give different 
results than in 4.23 for these values, in `filter`, `choice`, `=~`, `contains` 
on a collection, and the Java DSL and mock predicates 
(`header("amount").isEqualTo("10")`). Users who want the text compared can use 
`equals`.
   - This is for main only: the older branches do not have the value comparison 
of CAMEL-25013.
   
   Who sees a difference: only a comparison where one side is a `Number` object 
(a JDBC `BigDecimal`, an integer JSON value, an `Integer` header) and the other 
side is a `String` with the same value written differently (`'10'` vs `10.00`, 
`'3.0'`, `' 7'`, `'1e3'`). A header that is a `String` compared with a quoted 
literal is `String` vs `String`, and that is unchanged. So are leading zeros 
with an `Integer` or `Long`: `7 == '007'` was already `true`. A phone number 
such as `"+4915112345678"` was already equal to the `Long` 4915112345678, 
through the type converter. No comparison that was `true` becomes `false`: I 
compared 385 number/text pairs in both orders, and 29 Simple, Java DSL and 
`contains` predicates, on main and with this change. Only the cases above 
changed, from `false` to `true` (and `!=` from `true` to `false`), plus the 
ordering of `" 9007199254740992"`.
   
   Tests:
   - `TypeCoerceCompareTest`: 
`testEqualsNumberAndNumericStringWrittenDifferently`, 
`testCompareNumberAndNumericStringWithSpaceOrExponent`, 
`testEqualsNumberAndTextThatIsNotANumber` and 
`testEqualsNumberAndTooLongNumericString`; 
`SimpleOperatorTest.testEqualsNumberWithNumericTextWrittenDifferently`. All 
five fail on main and pass with the change. 
`testEqualsNumberAndTooLongNumericString` also fails without the length limit. 
The negative cases of `testEqualsNumberAndTextThatIsNotANumber` (such as `-` or 
`2026-10-26`) pass on main too. They check that the form check before parsing 
does not change the result.
   - Offline, on main e4c4dbbeb5da with this change applied (the files of this 
commit are the same there as on its base aa63c0a4cb94): the whole of 
camel-core, 8238 tests, 0 failures, 45 skipped, 1 error in 
`ValidatorExternalResourceTest`, which loads an XSD from 
raw.githubusercontent.com and fails the same way on main without network access 
(2 file tests failed once on file timing and passed on the rerun); the tests of 
the other core modules, 450 tests, 0 failures. The formatter and import-sort 
plugins ran and changed nothing.
   
   How it was found: a differential fuzz harness of the Simple numeric 
operators (`==`, `!=`, `<`, `<=`, `>`, `>=`, `range`, `in` on typed 
`Integer`/`Long`/`Short`/`BigDecimal`/`BigInteger`/`String` headers against 
quoted, unquoted and header right sides, checked against a comparison of the 
values). Of 5 million inputs, 1,829 were wrong on main. Every one was `==` or 
`!=` of a number and a numeric `String` with the same value written 
differently, where `<=` and `>=` were both true. I ran the same 5 million 
inputs with this change in a second class loader: all 1,829 are now right and 
no other input gives a different result.
   
   # Target
   
   - [x] I checked that the commit is targeting the correct branch (Camel 4 
uses the `main` branch)
   
   # Tracking
   - [x] If this is a large change, bug fix, or code improvement, I checked 
there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL-26329) 
filed for the change (usually before you start working on it): 
[CAMEL-26329](https://issues.apache.org/jira/browse/CAMEL-26329).
   
   # Apache Camel coding standards and style
   
   - [x] I checked that each commit in the pull request has a meaningful 
subject line and body.
   - [ ] I have run `mvn clean install -DskipTests` locally from root folder 
and I have committed all auto-generated changes.
     (I ran the core module tests above with the formatter and import-sort 
plugins; no generated files are affected. I did not run the full root build.)
   
   # AI-assisted contributions
   
   - [x] If this PR includes AI-generated code, commits have proper 
co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR 
description identifies the AI tool used.
     This PR was prepared with Claude Code (Claude Opus 5.5). The commit 
carries a `Co-Authored-By` trailer.
   
   _Claude Code on behalf of allthingssecurity_
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to