dependabot[bot] opened a new pull request, #25370:
URL: https://github.com/apache/camel/pull/25370

   Bumps [com.cedarsoftware:java-util](https://github.com/jdereg/java-util) 
from 4.109.0 to 4.110.0.
   <details>
   <summary>Release notes</summary>
   <p><em>Sourced from <a 
href="https://github.com/jdereg/java-util/releases";>com.cedarsoftware:java-util's
 releases</a>.</em></p>
   <blockquote>
   <h2>4.110.0</h2>
   <h2>java-util 4.110.0</h2>
   <p>Maven Central: <code>com.cedarsoftware:java-util:4.110.0</code></p>
   <p>Three conversion correctness fixes, all found while building 
decision-table type inference in <a 
href="https://github.com/jdereg/n-cube";>n-cube</a> — which asks the Converter 
whether a value survives a type change, and could not trust the answers.</p>
   <h3>Conversion correctness</h3>
   <p><strong><code>&quot;yes&quot;</code> converted to 
<code>false</code>.</strong> The truth set accepted 
<code>&quot;true&quot;</code>, <code>&quot;t&quot;</code>, 
<code>&quot;1&quot;</code> and <code>&quot;y&quot;</code> — but not the 
spelled-out word. So <code>&quot;y&quot;</code> was <code>true</code> while 
<code>&quot;Yes&quot;</code> was <strong><code>false</code></strong>. Not a 
rejection but an <em>inversion</em>, and a silent one, since anything 
unrecognised returns <code>false</code> rather than throwing: text written the 
long way read as the exact opposite of what it said. 
<code>&quot;yes&quot;</code> now joins <code>&quot;y&quot;</code>, 
case-insensitively.</p>
   <p><strong><code>Float</code> → <code>Double</code> and <code>Float</code> → 
<code>BigDecimal</code> widened through the bits.</strong> <code>3.7f</code> 
became <code>3.700000047683716</code>; <code>0.1f</code> became 
<code>0.10000000149011612</code>. Widening now goes through 
<code>Float.toString()</code>, which emits the shortest decimal that uniquely 
identifies the float, so <code>3.7f</code> becomes <code>3.7</code>. 
<strong>Nothing is lost</strong> — every value still converts back to the 
identical float, extremes included; only <em>which</em> of the doubles mapping 
to that float you land on changes, and the one that prints as the float prints 
is the one that was meant. <code>BigDecimal</code> was the worse case: a type 
whose whole purpose is exact decimal representation was being handed the binary 
error.</p>
   <p><strong><code>BigDecimal</code> → <code>String</code> stripped the 
scale.</strong> <code>new BigDecimal(&quot;1.50&quot;)</code> rendered as 
<code>&quot;1.5&quot;</code>, so <code>BigDecimal → String → BigDecimal</code> 
returned a value not <code>equals()</code> to the original — BigDecimal 
equality includes scale. Scale is information: it separates an amount written 
to the cent from the same quantity written to the tenth. Now 
<code>toPlainString()</code>, which keeps the scale and still never emits 
scientific notation.</p>
   <h3>Behaviour changes to be aware of</h3>
   <ul>
   <li><code>Float.MAX_VALUE</code> → <code>Double</code> is now 
<code>3.4028235E38</code> rather than <code>3.4028234663852886E38</code>.</li>
   <li>Any caller rendering a <code>BigDecimal</code> through the Converter now 
sees trailing zeros preserved.</li>
   </ul>
   <p>Integral targets are unaffected — 
<code>Float</code>/<code>Double</code>/<code>BigDecimal</code> → 
<code>Long</code>/<code>BigInteger</code> still truncate, which is inherent to 
discarding a fraction. <code>DeepEquals</code> deliberately still normalises 
trailing zeros, because <em>comparison</em> should treat <code>1.50</code> and 
<code>1.5</code> as equal even though <em>rendering</em> should not.</p>
   <h3>Testing</h3>
   <p>The <code>performRelease</code> benchmarks now <strong>detect 
regressions</strong> instead of printing numbers nobody compares, and the four 
slowest test classes got <strong>9x faster</strong> — roughly 80 seconds of 
every release build sat in tests with no assertions at all. See the changelog 
for the full account.</p>
   <h3>Build</h3>
   <p><code>maven-jar-plugin</code> 3.5.0 → 3.5.1, 
<code>maven-bundle-plugin</code> 6.0.2 → 6.1.0. JUnit (5.14.4), Mockito 
(4.11.0) and agrona (1.23.1) are each already the newest release in the series 
their JDK 8 support pins them to.</p>
   <hr />
   <p>20,411 tests green. Verified against <a 
href="https://github.com/jdereg/json-io";>json-io</a>'s full suite (4,748 tests) 
before publishing.</p>
   </blockquote>
   </details>
   <details>
   <summary>Changelog</summary>
   <p><em>Sourced from <a 
href="https://github.com/jdereg/java-util/blob/master/changelog.md";>com.cedarsoftware:java-util's
 changelog</a>.</em></p>
   <blockquote>
   <h4>4.110.0 - 2026-08-02</h4>
   <ul>
   <li><strong>CONVERSION (correctness)</strong>: 
<strong><code>Converter.convert()</code> silently inverted 
<code>&quot;Yes&quot;</code> and silently mangled every 
<code>Float</code>.</strong> Both were found while building decision-table type 
inference in n-cube, which asks the Converter whether a value survives a type 
change; it could not trust either answer.
   <ul>
   
<li><strong><code>&quot;yes&quot;</code>/<code>&quot;Yes&quot;</code>/<code>&quot;YES&quot;</code>
 converted to <code>false</code>.</strong> The truth set accepted 
<code>&quot;true&quot;</code>, <code>&quot;t&quot;</code>, 
<code>&quot;1&quot;</code> and <code>&quot;y&quot;</code> — but not the 
spelled-out word. So <code>&quot;y&quot;</code> was <code>true</code> while 
<code>&quot;Yes&quot;</code> was <strong><code>false</code></strong>: not a 
rejection, an <strong>inversion</strong>, and a silent one, since anything 
unrecognised returns <code>false</code> rather than throwing. Any data written 
the long way read as the opposite of what it said, which for the No/Yes answers 
commonly held in decision-table output columns would have flipped every 
affirmative. <code>&quot;yes&quot;</code> now joins <code>&quot;y&quot;</code>, 
case-insensitively; <code>&quot;no&quot;</code> was already <code>false</code> 
(though only because everything unmatched is).</li>
   <li><strong><code>Float</code> → <code>Double</code> and <code>Float</code> 
→ <code>BigDecimal</code> widened through the bits instead of the 
decimal.</strong> <code>3.7f</code> became <code>3.700000047683716</code> and 
<code>0.1f</code> became <code>0.10000000149011612</code>, because 
<code>Float.doubleValue()</code> faithfully preserves the binary approximation 
rather than the number the author wrote. Widening now goes through 
<code>Float.toString()</code>, which by contract emits the shortest decimal 
that uniquely identifies the float, so <code>3.7f</code> becomes 
<code>3.7</code>. <strong>Nothing is lost:</strong> every value still converts 
back to the identical float, including <code>Float.MIN_VALUE</code> and 
<code>Float.MAX_VALUE</code>; what changes is only <em>which</em> of the 
doubles that map back to that float you land on, and the one that prints as the 
float prints is the one that was meant. <code>BigDecimal</code> was the worse 
of the two — a type whose entire 
 purpose is exact decimal representation was being handed the binary error. 
<strong>Behaviour change at the extremes:</strong> <code>Float.MAX_VALUE</code> 
→ <code>Double</code> is now <code>3.4028235E38</code> rather than 
<code>3.4028234663852886E38</code>. The 
<code>Float</code>→<code>BigDecimal</code> test cases had been chosen as 
exactly-representable values with the comment <em>&quot;Changed to avoid float 
precision issues&quot;</em> — the defect was being worked around rather than 
reported.</li>
   <li>Integral targets are unaffected: 
<code>Float</code>/<code>Double</code>/<code>BigDecimal</code> → 
<code>Long</code>/<code>BigInteger</code> still truncate, which is inherent to 
discarding a fraction.</li>
   <li>New cases live in the shared <code>ConverterEverythingTest</code> table, 
so they are exercised through every path — direct conversion, JSON-IO 
round-trip, and TOON.</li>
   <li><strong><code>BigDecimal</code> → <code>String</code> no longer strips 
the scale.</strong> It called <code>stripTrailingZeros()</code> first, so 
<code>new BigDecimal(&quot;1.50&quot;)</code> rendered as 
<code>&quot;1.5&quot;</code> — which broke round-tripping, because 
<code>BigDecimal</code> equality <strong>includes scale</strong>, so 
<code>BigDecimal → String → BigDecimal</code> returned a value not 
<code>equals()</code> to the original. Scale is information: it is what 
separates a money amount written to the cent from the same quantity written to 
the tenth. Now <code>toPlainString()</code>, which keeps the scale and still 
never emits scientific notation — the property the old implementation was 
really relying on. <strong>Behaviour change:</strong> any caller rendering a 
<code>BigDecimal</code> through the Converter now sees trailing zeros 
preserved. The blast radius is exactly one registration; nothing else reaches 
this method, and the <code>stripTrailingZeros()<
 /code> in <code>DeepEquals</code> is deliberately untouched because 
<em>comparison</em> should treat 1.50 and 1.5 as equal even though 
<em>rendering</em> should not.</li>
   </ul>
   </li>
   <li><strong>BUILD</strong>: <code>maven-jar-plugin</code> 3.5.0 → 3.5.1, 
<code>maven-bundle-plugin</code> 6.0.2 → 6.1.0. JUnit (5.14.4), Mockito 
(4.11.0) and agrona (1.23.1) are each already the newest release in the series 
their JDK-8 support pins them to; <code>json-io</code> stays one release behind 
(4.108.0) by the trail-by-one rule that keeps the two projects from 
cycling.</li>
   <li><strong>TESTING</strong>: <strong>The <code>performRelease</code> 
benchmarks now detect performance regressions instead of printing numbers 
nobody compares — and the four slowest test classes got 9x faster.</strong> 
They previously burned ~110 seconds of every release build, and roughly 80 of 
those seconds sat in tests with <strong>no assertions at all</strong>: they 
could not fail, could not detect a regression, and produced absolute 
millisecond figures that are not comparable between a dev laptop, a CI runner, 
and the release machine. A human had to read the log and remember last 
release's numbers.
   <ul>
   <li><strong>New <code>PerfRatchet</code> test harness</strong> records each 
benchmark as a <strong>ratio against a yardstick workload measured in the same 
JVM run, interleaved trial-for-trial</strong> — <code>CaseInsensitiveMap</code> 
against the <code>LinkedHashMap</code> it wraps, Cedar's 
<code>MultiKeyMap</code> against Apache Commons', the caches against 
<code>HashMap</code>/<code>LinkedHashMap</code>. Machine speed divides out, so 
<code>1.85x</code> means &quot;1.85 times the cost of the JDK equivalent&quot; 
on any hardware. 19 metrics are tracked in 
<code>src/test/resources/perf-baseline.properties</code>.</li>
   <li><strong>Nothing fails the build.</strong> Verdicts are <code>OK</code> / 
<code>IMPROVED</code> / <code>REGRESSED</code> / <code>NEW</code>, logged and 
written to <code>target/perf-report.tsv</code>; a regression is a WARNING, not 
a test failure, because turning normal variance into a red build is how a perf 
signal gets ignored. <code>-Dperf.strict=true</code> opts into failing, for a 
machine whose numbers you trust.</li>
   <li><strong>The ratchet locks in gains.</strong> 
<code>-Dperf.baseline.update=true</code> writes improvements back and never 
writes a regression, so the bar only moves toward faster. 
<code>-Dperf.baseline.reset=true</code> writes every metric in either 
direction, because a pure ratchet cannot repair itself — a baseline first 
captured from an unluckily <em>fast</em> reading would report a regression 
forever and update mode by definition will not raise it back.</li>
   <li><strong>Self-calibrating bars.</strong> Each metric publishes the 
interquartile scatter of its own trials, and the regression/improvement bar is 
the configured floor <em>or</em> that scatter, whichever is larger. A metric 
whose trials disagreed by 35% cannot credibly report a 25% change; one that 
measured to 3% is held to the tight floor. This is what lets noisy 
allocation-heavy benchmarks coexist with precise ones without slackening the 
threshold for everybody. An improvement must also clear the noise floor before 
it can be ratcheted in, so a lucky outlier cannot move the bar out of 
reach.</li>
   <li><strong>Measurement fixes found along the way.</strong> Warmup must 
cover <em>every</em> variant sharing a lambda body before any is measured 
(<code>PerfRatchet.warmAll</code>), or whichever runs first absorbs the JIT 
cost for all of them — that artifact alone was inflating one metric's noise 
from ~10% to 63%. Baselines must be calibrated from a <strong>full 
suite</strong> run: the same metrics scattered 2-15% in isolation and 5-68% 
alongside the other ~20,000 tests. <code>LRUCache</code>'s THREADED strategy is 
deliberately <strong>not</strong> tracked — its ratio ranged 1.14x-3.48x across 
identical runs because a background cleanup thread services its reads, and that 
variance is invisible within a single run, so it would report confident 
regressions on nothing but thread scheduling.</li>
   <li><strong><code>CaseInsensitiveMapTest</code> 53.1s → 0.63s.</strong> 
<code>testPerformance</code>/<code>testPerformance2</code> copied a 
10,000-entry map 100,000 times each — <strong>two billion entry copies</strong> 
— to print four numbers. They were already a matched 
CaseInsensitiveMap-vs-LinkedHashMap pair; they simply never divided one by the 
other. Separately, <code>testCaseInsensitiveMapPerformanceComparison</code> ran 
every workload <strong>twice</strong>: <code>timeMapOperations</code> for a 
fixed 2000 ms, then <code>countOps</code> — a byte-for-byte copy of it plus a 
counter — for another 2000 ms. Since the loop budget <em>was</em> 2000 ms, the 
&quot;time&quot; it measured was always ≈2000 by construction, which is why 
every line of its output read &quot;operations in 2,000 ms&quot;. <strong>Half 
that test's 24 seconds computed a constant.</strong></li>
   <li><strong><code>MultiKeyMapPerformanceComparisonTest</code> 25.1s → 
0.90s.</strong> A 6x7 matrix up to 250,000 entries, ten iterations, both 
implementations: ~105 million map operations, plus a 
<code>Thread.sleep(100)</code> and an explicit <code>System.gc()</code> per 
configuration (4.2 seconds of sleeping, 42 forced collections). Two of the 
seven data sizes accounted for 80% of the work while adding nothing the smaller 
sizes did not show.</li>
   <li><strong><code>LRUCacheTest</code> 21.8s → 7.5s.</strong> 
<code>testCacheBlast</code> put 10,000,000 entries per strategy into a 
<strong>1000-entry</strong> cache — 99.99% evicted on arrival — to assert one 
number; 200,000 puts is still 200x capacity. <code>testSpeed</code> put another 
10,000,000 per strategy (~800MB each, per its own comment) and asserted 
nothing. The <code>@AfterEach</code> <code>System.gc()</code> meant ~60 forced 
full collections across the class and is gone.</li>
   <li><strong><code>TTLCacheTest</code> 10.1s → 2.7s.</strong> 9.4 of its 10.1 
seconds were <code>Thread.sleep</code>. One test already demonstrated the fast 
idiom (200ms TTL, 100ms purge, 350ms wait) while four others used 10x larger 
values to prove the same properties; they now match. Total sleep is 1.9s.</li>
   <li><strong>Two findings worth knowing.</strong> 
<code>CaseInsensitiveMap(TreeMap)</code> is ~1.2-1.3x <strong>slower</strong> 
than plain <code>TreeMap(String.CASE_INSENSITIVE_ORDER)</code> — you pay for 
key wrapping <em>and</em> case-insensitive comparison — so a sorted 
case-insensitive map is better served by the JDK directly; the 
<code>HashMap</code>/<code>LinkedHashMap</code>-backed variants are 3x and 7x 
<em>faster</em> than that same TreeMap. And <code>CaseInsensitiveMap</code>'s 
copy constructor runs at parity (~1.0x) with <code>LinkedHashMap</code>'s, 
confirming the <code>CaseInsensitiveString</code> key-reuse optimization pays 
off. Both are now tracked.</li>
   <li><code>scripts/extract-perf-results.sh</code> renders the tracked metrics 
from the TSV, since the summary block is printed by a JVM shutdown hook that 
fires after Surefire stops capturing stdout and so never reaches the deploy 
log. <strong>No production code changed</strong> — this is test infrastructure 
only. Suite green: 20,380 tests (release mode), 20,377 (normal).</li>
   </ul>
   </li>
   </ul>
   </blockquote>
   </details>
   <details>
   <summary>Commits</summary>
   <ul>
   <li><a 
href="https://github.com/jdereg/java-util/commit/f6b1400d7c6b313379b82cbfca241f147321e8fd";><code>f6b1400</code></a>
 Docs: state the 4.110.0 discovery context without naming the customer</li>
   <li><a 
href="https://github.com/jdereg/java-util/commit/223b045bcd3e846b2d1b8fabf10248ad6bd4c3f4";><code>223b045</code></a>
 Fix: BigDecimal -&gt; String dropped the scale, so it could not round-trip</li>
   <li><a 
href="https://github.com/jdereg/java-util/commit/2e7e0cb906ccf04fdbf15ddc32a14aedbba06625";><code>2e7e0cb</code></a>
 Release: java-util 4.110.0</li>
   <li><a 
href="https://github.com/jdereg/java-util/commit/ad4eb504dcc34e88f521649508c5681044aaabfc";><code>ad4eb50</code></a>
 Fix: Converter turned &quot;Yes&quot; into false, and widened every Float 
through its bits</li>
   <li><a 
href="https://github.com/jdereg/java-util/commit/8be0815ff55052d0cb5a5e97623f2d342100b2f1";><code>8be0815</code></a>
 Test: performance benchmarks now detect regressions, and run 9x faster</li>
   <li><a 
href="https://github.com/jdereg/java-util/commit/3ea139b058c0fdd40fe7d1641513fa894eb9e3f5";><code>3ea139b</code></a>
 Fix: perf-results script reported nothing on macOS</li>
   <li>See full diff in <a 
href="https://github.com/jdereg/java-util/compare/4.109.0...4.110.0";>compare 
view</a></li>
   </ul>
   </details>
   <br />
   
   
   [![Dependabot compatibility 
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=com.cedarsoftware:java-util&package-manager=maven&previous-version=4.109.0&new-version=4.110.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
   
   Dependabot will resolve any conflicts with this PR as long as you don't 
alter it yourself. You can also trigger a rebase manually by commenting 
`@dependabot rebase`.
   
   [//]: # (dependabot-automerge-start)
   [//]: # (dependabot-automerge-end)
   
   ---
   
   <details>
   <summary>Dependabot commands and options</summary>
   <br />
   
   You can trigger Dependabot actions by commenting on this PR:
   - `@dependabot rebase` will rebase this PR
   - `@dependabot recreate` will recreate this PR, overwriting any edits that 
have been made to it
   - `@dependabot show <dependency name> ignore conditions` will show all of 
the ignore conditions of the specified dependency
   - `@dependabot ignore this major version` will close this PR and stop 
Dependabot creating any more for this major version (unless you reopen the PR 
or upgrade to it yourself)
   - `@dependabot ignore this minor version` will close this PR and stop 
Dependabot creating any more for this minor version (unless you reopen the PR 
or upgrade to it yourself)
   - `@dependabot ignore this dependency` will close this PR and stop 
Dependabot creating any more for this dependency (unless you reopen the PR or 
upgrade to it yourself)
   
   
   </details>


-- 
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