Skip to content

Java 21 review: correctness/security fixes plus java.time, record, and secure-cipher additions#23

Merged
marevol merged 2 commits into
masterfrom
review/corelib-fixes-20260703
Jul 4, 2026
Merged

Java 21 review: correctness/security fixes plus java.time, record, and secure-cipher additions#23
marevol merged 2 commits into
masterfrom
review/corelib-fixes-20260703

Conversation

@marevol

@marevol marevol commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Java 21 review of the core utilities. Two commits:

  1. fix(core) — correctness, thread-safety, and security bug fixes (backward-compatible only), with regression tests.
  2. feat(core) — additive enhancements: java.time conversions, record support, and opt-in secure APIs. No existing behavior or defaults change.

mvn clean test707 tests, 0 failures.

Fixes (backward-compatible)

collection

  • ArrayMap.clone() rebuilds the hash table instead of truncating it to the element count (corrupted get/remove, could throw ArrayIndexOutOfBoundsException on a later put).
  • LruHashSet / CaseInsensitiveSet implement writeObject/readObject (were unserializable / restored to a null map).
  • CaseInsensitiveMap accepts null keys and lowercases with Locale.ROOT.

misc / lang

  • DynamicProperties: fixed a reload-throttle bug that disabled change detection under frequent access; delegated the Map default methods to the backing store; used mkdirs().
  • SystemUtil / LocaleUtil use volatile suppliers; ClassUtil.newInstance uses getDeclaredConstructor(); StringUtil.replace guards an empty search string; plus small modernizations.

io / nio / net

  • FileUtil.readBytes reads until the buffer is filled or EOF (a short FileChannel.read returned zero-padded data); added a 2 GB guard.
  • ChannelUtil loops transferTo until the whole source is copied.
  • SerializeUtil's default deserialization filter enforces depth / reference / stream-byte / array-length limits.
  • Preserve a literal + when decoding URL / resource / jar / zip paths.

crypto / convert / beans / timer / xml / log / security

  • CachedCipher re-initializes a pooled cipher with the current key on every operation and clears the pool on config change.
  • TimestampConversionUtil honors the Locale; DecimalFormatSymbolsUtil returns a clone.
  • BeanDescImpl no longer mutates the caller's args during overload resolution; BeanDescFactory deregisters its cache disposable on clear().
  • TimeoutManager fixes a thread-clear race; TimeoutTask fields are volatile; SchemaFactoryUtil enables secure processing; Logger is null-safe.

Enhancements (additive — no behavior change)

  • convert: new TemporalConversionUtil converts Date / Calendar / epoch-millis / ISO-8601 strings and java.time values to LocalDate / LocalDateTime / LocalTime / Instant / OffsetDateTime / ZonedDateTime (system-default zone, or an explicit ZoneId).
  • beans: BeanDescImpl detects record components as read-only properties and instantiates records through their canonical constructor. Non-record beans are unchanged.
  • crypto: CachedCipher.encryptWithIv / decryptWithIv provide AES/GCM authenticated encryption with a fresh random IV per call, as an opt-in alternative to the pooled Blowfish/ECB methods (which are unchanged). The caller supplies the AES Key.
  • io: CloseableUtil.closeAndRethrow propagates close failures (for output streams, where a swallowed close = data loss); FileUtil.isRealPathSafe resolves symbolic links via toRealPath. Existing close/closeQuietly and isPathSafe are unchanged.
  • exception: InvalidAlgorithmParameterRuntimeException (message ECL0117).

Deferred (not in this PR — would change observable behavior or public API)

Left out to preserve backward compatibility; each needs a deliberate decision, ideally under a major version bump:

  • CachedCipher default mode (ECB) — changing it would break decryption of existing ciphertext (the new opt-in AES/GCM API above is the compatible path).
  • StringUtil.appendHex(int) zero-padding — an existing test and UuidUtil depend on the current output.
  • UuidUtil uniqueness — the generated random part is effectively 32 bits; strengthening it changes the string format.
  • Logger SLF4J backend, ArrayMap equals/hashCode contract, URLUtil new URL(...)URI.toURL(), SLinkedList.remove(int) return type, CloseableUtil.close semantics — behavior/API changes for follow-up.

Testing

Regression tests were added for the high-severity fixes and for every new API. mvn clean test passes with 707 tests.

marevol added 2 commits July 4, 2026 05:40
…n tests

Address review findings across core utilities while preserving backward
compatibility. Behavior- and format-changing items (e.g. cipher default
mode, UUID format, equals/hashCode contracts) are intentionally deferred.

collection:
- ArrayMap.clone() rebuilds buckets instead of truncating the hash table
- LruHashSet/CaseInsensitiveSet implement writeObject/readObject
- CaseInsensitiveMap handles null keys and lowercases with Locale.ROOT

misc/lang:
- DynamicProperties: fix reload throttle, delegate Map default methods,
  create parent directories with mkdirs()
- SystemUtil/LocaleUtil use volatile suppliers; ClassUtil.newInstance uses
  getDeclaredConstructor(); StringUtil.replace guards empty search text

io/nio/net:
- FileUtil.readBytes reads until the buffer is filled or EOF
- ChannelUtil loops transferTo until the whole source is copied
- SerializeUtil default filter enforces depth/refs/bytes/array-length limits
- Preserve a literal '+' when decoding URL/resource/jar/zip paths

crypto/convert/beans/timer/xml/log/security:
- CachedCipher re-initializes pooled ciphers per key; clears pool on config change
- TimestampConversionUtil honors the locale; DecimalFormatSymbolsUtil returns a clone
- BeanDescImpl no longer mutates caller args during method resolution;
  BeanDescFactory deregisters its cache disposable on clear()
- TimeoutManager fixes the thread-clear race; TimeoutTask fields are volatile
- SchemaFactoryUtil enables secure processing; Logger is null-safe

Adds regression tests for the high-severity fixes.
…ure APIs

Additive enhancements that do not change any existing behavior or defaults.

- convert: new TemporalConversionUtil converts Date/Calendar/epoch-millis/ISO
  strings and java.time values to LocalDate/LocalDateTime/LocalTime/Instant/
  OffsetDateTime/ZonedDateTime (system-default zone, or an explicit ZoneId)
- beans: BeanDescImpl detects record components as read-only properties and
  instantiates records through their canonical constructor
- crypto: CachedCipher.encryptWithIv/decryptWithIv provide AES/GCM authenticated
  encryption with a fresh random IV per call; the default Blowfish/ECB pool is
  left unchanged
- io: CloseableUtil.closeAndRethrow propagates close failures (for output
  streams); FileUtil.isRealPathSafe resolves symbolic links via toRealPath
- exception: add InvalidAlgorithmParameterRuntimeException (message ECL0117)

Adds regression tests for all new APIs.
@marevol marevol changed the title fix(core): fix correctness, thread-safety, and security bugs with regression tests Java 21 review: correctness/security fixes plus java.time, record, and secure-cipher additions Jul 3, 2026
@marevol marevol merged commit 670b6dc into master Jul 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant