Skip to content

Releases: jdereg/java-util

4.98.0

08 Mar 16:40

Choose a tag to compare

Changes

  • PERFORMANCE: CaseInsensitiveMap.get(), containsKey(), and remove() now use a ThreadLocal<LookupKey> for String key lookups on hash-based backings (HashMap, LinkedHashMap, ConcurrentHashMap), eliminating per-call CaseInsensitiveString allocation. This removes the single largest remaining allocation cost center (403 JFR samples). LookupKey is a lightweight mutable object reused via ThreadLocal, with bidirectional equals support for both HashMap and ConcurrentHashMap lookup directions. SortedMap backings continue to use CaseInsensitiveString since they require Comparable keys.
  • PERFORMANCE: CaseInsensitiveMap now overrides size() and isEmpty() to delegate directly to the backing map, bypassing the AbstractMap.size()entrySet().size() indirection chain (168 JFR samples eliminated).
  • PERFORMANCE: CaseInsensitiveMap internal fields changed from private to package-private to eliminate JVM synthetic accessor methods generated for anonymous inner class access (40 JFR samples eliminated).
  • PERFORMANCE: StringUtilities.hashCodeIgnoreCase() now inlines the case-fold logic directly into the hash loop, ensuring C2 JIT compiles the entire loop as a single compilation unit.
  • PERFORMANCE: StringUtilities.foldCaseForHash() branch ordering optimized to check c <= 'Z' first, partitioning ASCII so uppercase and lowercase each take only two comparisons.
  • BUG FIX: ConverterDurationToOffsetDateTimeTest used the current system timezone offset to compute expected values, but the conversion target is the epoch (1970). Fixed to compute the offset at the actual target instant.
  • TESTING: Added ToonRoundTripTest — 46 parameterized tests verifying all Converter-supported types round-trip through TOON format.
  • TESTING: Added ConverterDurationToOffsetDateTimeTest — verifies Duration → OffsetDateTime conversion across multiple scenarios.

Maven:

<dependency>
  <groupId>com.cedarsoftware</groupId>
  <artifactId>java-util</artifactId>
  <version>4.98.0</version>
</dependency>

4.97.0

08 Mar 16:40

Choose a tag to compare

Changes

  • PERFORMANCE: FastReader.readUntil() now splits the inner loop into a read-only delimiter scan followed by a bulk System.arraycopy, allowing the JIT to optimize the tight scan loop independently from memory writes.
  • PERFORMANCE: FastReader.readUntil() scan loop now uses a do-while with a single array access per iteration and hoists position assignment above the delimiter check to eliminate a duplicate write.

Maven:

<dependency>
  <groupId>com.cedarsoftware</groupId>
  <artifactId>java-util</artifactId>
  <version>4.97.0</version>
</dependency>

4.96.0

01 Mar 14:16

Choose a tag to compare

Bug Fix

  • ClassUtilities.trySetAccessible() no longer caches successful setAccessible(true) results. The WeakHashMap-based cache uses equals() for lookup, but Field.equals() matches by declaring class, name, and type — not identity. When getDeclaredFields() was called with different predicates, the JVM returned different Field instances for the same logical field; the cache returned TRUE for the second instance without ever calling setAccessible(true) on it, leaving it inaccessible. This caused Traverser to silently skip inaccessible fields, breaking GraphComparator.applyDelta(). Only failures (FALSE) are now cached to avoid expensive repeated exceptions on JPMS-sealed modules.

Install

Maven

<dependency>
  <groupId>com.cedarsoftware</groupId>
  <artifactId>java-util</artifactId>
  <version>4.96.0</version>
</dependency>

Gradle

implementation 'com.cedarsoftware:java-util:4.96.0'