WW-5668 Bound the localized-text provider caches and align request-locale resolution - #1821
Open
lukaszlenart wants to merge 11 commits into
Open
WW-5668 Bound the localized-text provider caches and align request-locale resolution#1821lukaszlenart wants to merge 11 commits into
lukaszlenart wants to merge 11 commits into
Conversation
…resolution Follow-up to WW-5540. Bound the AbstractLocalizedTextProvider caches via the existing OgnlCache abstraction (configurable struts.i18n.cacheType/cacheMaxSize), and add opt-in request-locale resolution consistency between Dispatcher and I18nInterceptor (struts.locale.validateRequestLocale, default off). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-locale resolution Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ields synchronized (bundlesMap) locked on a monitor that rebuildI18nCaches() can reassign; introduce a dedicated bundlesMapLock and lock on that instead. Mark the five i18n cache fields volatile for safe publication across the reassignment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s serializable Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the one-line Javadoc that sibling fields/setters carry to validateRequestLocale and its @Inject setter in Dispatcher, and add two tests covering StrutsLocalizedTextProvider's serialize/deserialize cache rebuild and cacheType selection behaviour. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
lukaszlenart
force-pushed
the
WW-5668-i18n-cache-bounds
branch
from
July 30, 2026 11:00
e02aac2 to
089d9c3
Compare
…aches Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…le tests Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
lukaszlenart
marked this pull request as ready for review
July 30, 2026 11:49
lukaszlenart
requested review from
aleksandr-m,
cnenning,
Copilot,
jogep,
kusalk,
rgielen,
sdutry and
yasserzamani
July 30, 2026 11:50
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates Struts’ localized-text (i18n) subsystem to (1) bound and standardize the internal localized-text provider caches using the existing OgnlCache abstraction, and (2) optionally make request-locale resolution in Dispatcher consistent with I18nInterceptor by validating request-derived locales against the JVM available-locale set.
Changes:
- Replaced five unbounded
ConcurrentHashMap-based caches inAbstractLocalizedTextProviderwith configurable, boundedOgnlCacheinstances (struts.i18n.cacheType,struts.i18n.cacheMaxSize) and ensured caches rebuild after deserialization. - Added an additive
remove(K)operation toOgnlCacheand implemented it across cache implementations to support existing bundle-clearing behavior. - Added
struts.locale.validateRequestLocale(defaultfalse) and routedDispatcher’s request-locale selection through a helper that can validate/fallback when enabled, plus accompanying tests.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| docs/superpowers/specs/2026-07-30-WW-5668-i18n-cache-bounds-locale-resolution-design.md | New design spec documenting bounded i18n caches and opt-in request-locale validation behavior. |
| docs/superpowers/plans/2026-07-30-WW-5668-i18n-cache-bounds-locale-resolution.md | New implementation plan detailing the steps, constants, and tests for the change set. |
| core/src/main/java/org/apache/struts2/ognl/OgnlCache.java | Adds remove(K) to the cache abstraction to support bundle cache entry removal. |
| core/src/main/java/org/apache/struts2/ognl/OgnlCaffeineCache.java | Implements remove(K) for the Caffeine-backed cache. |
| core/src/main/java/org/apache/struts2/ognl/OgnlDefaultCache.java | Implements remove(K) for the default map-backed cache. |
| core/src/main/java/org/apache/struts2/ognl/OgnlLRUCache.java | Implements remove(K) for the LRU cache. |
| core/src/test/java/org/apache/struts2/ognl/OgnlCacheRemoveTest.java | New unit test validating remove(K) behavior across cache implementations. |
| core/src/main/java/org/apache/struts2/StrutsConstants.java | Adds new constants for i18n cache config and request-locale validation flag. |
| core/src/main/resources/org/apache/struts2/default.properties | Documents new configuration keys and defaults for i18n caches and locale validation. |
| core/src/main/java/org/apache/struts2/text/AbstractLocalizedTextProvider.java | Converts internal i18n caches to bounded OgnlCache instances; adds rebuild/readObject logic and cache size accessors for tests. |
| core/src/main/java/org/apache/struts2/text/StrutsLocalizedTextProvider.java | Adds serialVersionUID to align with serialization changes/expectations. |
| core/src/main/java/org/apache/struts2/text/GlobalLocalizedTextProvider.java | Adds serialVersionUID to align with serialization changes/expectations. |
| core/src/test/java/org/apache/struts2/text/StrutsLocalizedTextProviderTest.java | Adds tests for cache bounding, eviction correctness, reload clearing, deserialization usability, and cache-type selection. |
| core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java | Adds validateRequestLocale flag and resolveRequestLocale() helper; routes getLocale() request-locale retrieval through the helper. |
| core/src/test/java/org/apache/struts2/dispatcher/DispatcherTest.java | Adds tests for the new request-locale validation flag (off/on/invalid fallback behavior). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
948
to
949
| LOG.warn(new ParameterizedMessage("Cannot convert 'struts.locale' = [{}] to proper locale, defaulting to request locale [{}]", | ||
| defaultLocale, locale), e); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Fixes WW-5668
Follow-up to WW-5540. Two related, independent changes to the localized-text subsystem.
1. Bounded localized-text caches
AbstractLocalizedTextProviderkept its five internal caches (bundlesMap,messageFormats,missingBundles, and theclassHierarchyCache/packageHierarchyCacheadded in WW-5540) as plainConcurrentHashMaps with no configurable upper bound or eviction. The rest of the framework already standardises on bounded caches viaOgnlCacheFactory(struts.ognl.expressionCacheMaxSize,struts.proxy.cacheMaxSize, bothwtlfu); these were the outlier.OgnlCacheabstraction (DefaultOgnlCacheFactory) for all five caches, with configurable size and eviction.struts.i18n.cacheType(defaultwtlfu) andstruts.i18n.cacheMaxSize(default10000), documented indefault.properties.remove(key)toOgnlCache(needed byclearBundle).transientand rebuilt inreadObjectso the provider stays serializable; a dedicated lock replaces synchronizing on the now-reassignablebundlesMap.All five caches are pure/reconstructible, so eviction can only cause a recompute, never a wrong or stale localized result.
2. Consistent request-locale resolution (opt-in)
I18nInterceptorvalidates a resolved locale against the available-locale set (LocaleProvider.isValidLocale), butDispatcher.getLocale(...)(used whenstruts.localeis unset) returnsrequest.getLocale()directly without that check.struts.locale.validateRequestLocale(defaultfalse— current behaviour preserved byte-for-byte). When enabled,Dispatcherresolves request-derived locales against the JVM available-locale set, falling back to the configuredstruts.locale(else the JVM default), consistent withI18nInterceptor.Testing
findText, cache-type selection, and the threeDispatcherflag states (off / on-available / on-fallback).coresuite green.Backward compatibility
🤖 Generated with Claude Code