lukaszlenart commented on code in PR #1808:
URL: https://github.com/apache/struts/pull/1808#discussion_r3638055400


##########
core/src/main/java/org/apache/struts2/text/StrutsLocalizedTextProvider.java:
##########
@@ -65,6 +65,11 @@ public String findText(Class<?> startClazz, String textKey, 
Locale locale, Strin
             LOG.debug("Key is null, short-circuit to default message");
             return defaultMessage;
         }
+
+        // Trigger bundle reload (and cache invalidation) once, before any 
cached hierarchy lookup,
+        // so that in reload/devMode the hierarchy caches are cleared before 
they are read.
+        reloadBundles(valueStack != null ? valueStack.getContext() : null);

Review Comment:
   Good catch — this was also flagged by an internal review pass and fixed in 
e4166f876 (before this comment was posted): when the value stack is null, 
`findText` now falls back to the ActionContext-based `reloadBundles()` 
overload, so the `RELOADED` flag is tracked and the caches can warm on that 
path.



##########
core/src/main/java/org/apache/struts2/text/AbstractLocalizedTextProvider.java:
##########
@@ -90,6 +93,20 @@ protected ClassLoader getCurrentThreadContextClassLoader() {
         return Thread.currentThread().getContextClassLoader();
     }
 
+    private int currentLoaderHashCode() {
+        return getCurrentThreadContextClassLoader().hashCode();
+    }

Review Comment:
   Fixed in b04e0f416 — `currentLoaderHashCode()` now uses 
`System.identityHashCode(...)`. The pre-existing maps (`classLoaderMap`, 
`createMissesKey`) keep their `hashCode()`-based keying for now; the new caches 
don't share keys with them, so the divergence is safe.



##########
core/src/main/java/org/apache/struts2/text/AbstractLocalizedTextProvider.java:
##########
@@ -582,23 +628,113 @@ protected String findMessage(Class<?> clazz, String key, 
String indexedKey, Loca
         // traverse up hierarchy
         if (clazz.isInterface()) {
             interfaces = clazz.getInterfaces();
-
             for (Class<?> anInterface : interfaces) {
-                msg = findMessage(anInterface, key, indexedKey, locale, args, 
checked, valueStack);
-
+                msg = findMessageRaw(anInterface, key, indexedKey, locale, 
checked);
                 if (msg != null) {
                     return msg;
                 }
             }
         } else {
             if (!clazz.equals(Object.class) && !clazz.isPrimitive()) {
-                return findMessage(clazz.getSuperclass(), key, indexedKey, 
locale, args, checked, valueStack);
+                return findMessageRaw(clazz.getSuperclass(), key, indexedKey, 
locale, checked);
             }
         }
 
         return null;
     }
 
+    /**
+     * Cached resolution of the class/interface/superclass hierarchy for a 
key. Returns the raw pattern
+     * found, or {@link #NOT_FOUND} when the key is absent from the entire 
hierarchy. Keyed on the
+     * context classloader hash + class name + key + locale, so no {@link 
Class} reference is retained.
+     * Uses get + putIfAbsent (never computeIfAbsent) because the 
child-property path recurses into findText.
+     */
+    protected String resolveClassHierarchyRaw(Class<?> clazz, String textKey, 
String indexedKey, Locale locale) {
+        TextCacheKey cacheKey = new TextCacheKey(currentLoaderHashCode(), 
clazz.getName(), textKey, locale);
+        String cached = classHierarchyCache.get(cacheKey);

Review Comment:
   Fixed in b04e0f416 using the stronger variant you suggested: the 
`indexedKey` parameter was removed and the resolvers derive it internally via 
`extractIndexedName(textKey)` (miss-only), so the cache key now covers every 
input that influences the resolution result.



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