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>"yes"</code> converted to <code>false</code>.</strong> The truth set accepted <code>"true"</code>, <code>"t"</code>, <code>"1"</code> and <code>"y"</code> — but not the spelled-out word. So <code>"y"</code> was <code>true</code> while <code>"Yes"</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>"yes"</code> now joins <code>"y"</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("1.50")</code> rendered as <code>"1.5"</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>"Yes"</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>"yes"</code>/<code>"Yes"</code>/<code>"YES"</code> converted to <code>false</code>.</strong> The truth set accepted <code>"true"</code>, <code>"t"</code>, <code>"1"</code> and <code>"y"</code> — but not the spelled-out word. So <code>"y"</code> was <code>true</code> while <code>"Yes"</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>"yes"</code> now joins <code>"y"</code>, case-insensitively; <code>"no"</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>"Changed to avoid float precision issues"</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("1.50")</code> rendered as <code>"1.5"</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 "1.85 times the cost of the JDK equivalent" 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 "time" it measured was always ≈2000 by construction, which is why every line of its output read "operations in 2,000 ms". <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 -> 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 "Yes" 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 /> [](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]
