Lukasz Lenart created WW-5724:
---------------------------------

             Summary: Cached MessageFormat instances in 
AbstractLocalizedTextProvider are shared between concurrent callers
                 Key: WW-5724
                 URL: https://issues.apache.org/jira/browse/WW-5724
             Project: Struts 2
          Issue Type: Bug
            Reporter: Lukasz Lenart
             Fix For: 7.4.0, 6.12.0


h2. Summary

{{AbstractLocalizedTextProvider}} caches {{java.text.MessageFormat}} instances 
keyed by pattern and locale and returns the cached instance from 
{{buildMessageFormat}}, while {{DefaultTextProvider}} builds a fresh instance 
per call. {{MessageFormat}} is not thread-safe, so callers rendering the same 
message concurrently format through one shared instance.

h2. Current behaviour

{{buildMessageFormat}} returns the cached instance on a hit and 
{{formatWithNullDetection}} calls {{format()}} on it directly. The provider is 
a singleton bean, so the cache and every instance in it are shared 
application-wide. The sibling {{DefaultTextProvider.getText}} constructs a new 
{{MessageFormat}} on each call.

A pattern carrying a date or time sub-format delegates to a 
{{SimpleDateFormat}} held by the {{MessageFormat}}, which keeps per-call state 
in its {{Calendar}}; concurrent {{format()}} calls on the shared instance can 
render the wrong argument or throw. Number and choice sub-formats and plain 
placeholders are not affected on current JDKs.

h2. Proposed change

Keep the cache, but have {{buildMessageFormat}} return a clone of the cached 
instance, so the cached entry is only ever a template and is never formatted 
directly. {{MessageFormat.clone()}} deep-copies its sub-formats. This preserves 
the pattern-parsing cache the WW-5540 work relies on; measured against a fresh 
instance per call and against synchronizing on the shared instance, cloning is 
the cheapest of the three.

h2. Compatibility notes

No configuration or API change. Descendant classes that override 
{{buildMessageFormat}} keep their current behaviour; only the base 
implementation changes.

Applies to both maintenance lines.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to