You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ta...@apache.org on 2026/06/03 16:45:17 UTC

(myfaces) branch main updated: [perf] cache event listeners list, optimize popComponentFromEL

This is an automated email from the ASF dual-hosted git repository.

tandraschko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/main by this push:
     new f9d2a1566 [perf] cache event listeners list, optimize popComponentFromEL
f9d2a1566 is described below

commit f9d2a1566fb015ac8260507b42687d1e2e723b49
Author: tandraschko <ta...@apache.org>
AuthorDate: Wed Jun 3 18:45:07 2026 +0200

    [perf] cache event listeners list, optimize popComponentFromEL
---
 .../java/jakarta/faces/component/UIComponent.java  | 75 +++++++++++++---------
 .../jakarta/faces/component/UIComponentBase.java   | 40 +++++++-----
 2 files changed, 69 insertions(+), 46 deletions(-)

diff --git a/api/src/main/java/jakarta/faces/component/UIComponent.java b/api/src/main/java/jakarta/faces/component/UIComponent.java
index 7aa32a988..1e926acf5 100755
--- a/api/src/main/java/jakarta/faces/component/UIComponent.java
+++ b/api/src/main/java/jakarta/faces/component/UIComponent.java
@@ -119,7 +119,13 @@ public abstract class UIComponent
 
     private static final String _CURRENT_COMPOSITE_COMPONENT_KEY = "compositeComponent:" + UIComponent.class.getName();
 
-    Map<Class<? extends SystemEvent>, List<SystemEventListener>> _systemEventListenerClassMap;
+    Map<Class<? extends SystemEvent>, List<SystemEventListener>> _systemEventListeners;
+
+    // Cached unmodifiable views of _systemEventListeners entries.
+    // Created lazily; the whole cache is cleared whenever a backing list reference is
+    // replaced (full restore or non-delta entry in delta restore) — see UIComponentBase.
+    // Package-private so UIComponentBase can reset it after those restore operations.
+    transient Map<Class<? extends SystemEvent>, List<SystemEventListener>> _unmodifiableSystemEventListeners;
 
     /**
      * Used to cache the map created using getResourceBundleMap() method, since this method could be called several
@@ -442,25 +448,26 @@ public static UIComponent getCurrentCompositeComponent(FacesContext context)
     @Override
     public List<SystemEventListener> getListenersForEventClass(Class<? extends SystemEvent> eventClass)
     {
-        List<SystemEventListener> listeners;
-        if (_systemEventListenerClassMap == null)
+        if (_systemEventListeners == null)
         {
-            listeners = Collections.emptyList();
+            return Collections.emptyList();
         }
-        else
+        List<SystemEventListener> listeners = _systemEventListeners.get(eventClass);
+        if (listeners == null)
         {
-            listeners = _systemEventListenerClassMap.get(eventClass);
-            if (listeners == null)
-            {
-                listeners = Collections.emptyList();
-            }
-            else
-            {
-                listeners = Collections.unmodifiableList(listeners);
-            }
+            return Collections.emptyList();
         }
-
-        return listeners;
+        if (_unmodifiableSystemEventListeners == null)
+        {
+            _unmodifiableSystemEventListeners = new HashMap<>(4, 1f);
+        }
+        List<SystemEventListener> unmodifiableList = _unmodifiableSystemEventListeners.get(eventClass);
+        if (unmodifiableList == null)
+        {
+            unmodifiableList = Collections.unmodifiableList(listeners);
+            _unmodifiableSystemEventListeners.put(eventClass, unmodifiableList);
+        }
+        return unmodifiableList;
     }
 
     /**
@@ -801,16 +808,16 @@ public void subscribeToEvent(Class<? extends SystemEvent> eventClass,
         SystemEventListener listener = new _EventListenerWrapper(this, componentListener);
 
         // Make sure the map exists
-        if (_systemEventListenerClassMap == null)
+        if (_systemEventListeners == null)
         {
-            _systemEventListenerClassMap = new HashMap<>(4, 1f);
+            _systemEventListeners = new HashMap<>(4, 1f);
         }
 
-        List<SystemEventListener> listeners = _systemEventListenerClassMap.get(eventClass);
+        List<SystemEventListener> listeners = _systemEventListeners.get(eventClass);
         if (listeners == null)
         {
             listeners = new _DeltaList<>(3);
-            _systemEventListenerClassMap.put(eventClass, listeners);
+            _systemEventListeners.put(eventClass, listeners);
             listeners.add(listener);
         }
         else
@@ -840,9 +847,9 @@ public void unsubscribeFromEvent(Class<? extends SystemEvent> eventClass,
         Assert.notNull(eventClass, "eventClass");
         Assert.notNull(componentListener, "componentListener");
 
-        if (_systemEventListenerClassMap != null)
+        if (_systemEventListeners != null)
         {
-            List<SystemEventListener> listeners = _systemEventListenerClassMap.get(eventClass);
+            List<SystemEventListener> listeners = _systemEventListeners.get(eventClass);
             if (listeners != null && !listeners.isEmpty())
             {
                 for (Iterator<SystemEventListener> it = listeners.iterator(); it.hasNext(); )
@@ -1039,17 +1046,27 @@ public void popComponentFromEL(FacesContext context)
         UIComponent oldCurrent = null;
         if (componentStack != null && !componentStack.isEmpty())
         {
-            int componentIndex = componentStack.lastIndexOf(this);
-            if (componentIndex >= 0)
+            int lastIndex = componentStack.size() - 1;
+            if (componentStack.get(lastIndex) == this)
             {
-                for (int i = componentStack.size()-1; i >= componentIndex ; i--)
-                {
-                    oldCurrent = componentStack.remove(componentStack.size()-1);
-                }
+                // Fast path: balanced push/pop — this component is the top of the stack.
+                oldCurrent = componentStack.remove(lastIndex);
             }
             else
             {
-                return;
+                // Slow path: unbalanced pop (e.g. an intervening error skipped some pops).
+                int componentIndex = componentStack.lastIndexOf(this);
+                if (componentIndex >= 0)
+                {
+                    for (int i = lastIndex; i >= componentIndex; i--)
+                    {
+                        oldCurrent = componentStack.remove(componentStack.size() - 1);
+                    }
+                }
+                else
+                {
+                    return;
+                }
             }
         }
 
diff --git a/api/src/main/java/jakarta/faces/component/UIComponentBase.java b/api/src/main/java/jakarta/faces/component/UIComponentBase.java
index b804f9051..18f91fe1c 100755
--- a/api/src/main/java/jakarta/faces/component/UIComponentBase.java
+++ b/api/src/main/java/jakarta/faces/component/UIComponentBase.java
@@ -428,10 +428,10 @@ public void clearInitialState()
                 ((PartialStateHolder) entry.getValue()).clearInitialState();
             }
         }
-        if (_systemEventListenerClassMap != null)
+        if (_systemEventListeners != null)
         {
             for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener>> entry : 
-                _systemEventListenerClassMap.entrySet())
+                _systemEventListeners.entrySet())
             {
                 ((PartialStateHolder) entry.getValue()).clearInitialState();
             }
@@ -1186,10 +1186,10 @@ public void markInitialState()
                 ((PartialStateHolder) entry.getValue()).markInitialState();
             }
         }
-        if (_systemEventListenerClassMap != null)
+        if (_systemEventListeners != null)
         {
             for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener>> entry : 
-                _systemEventListenerClassMap.entrySet())
+                _systemEventListeners.entrySet())
             {
                 ((PartialStateHolder) entry.getValue()).markInitialState();
             }
@@ -2173,19 +2173,21 @@ private Object saveBehaviorsMap(FacesContext facesContext)
     @SuppressWarnings("unchecked")
     private void restoreFullSystemEventListenerClassMap(FacesContext facesContext, Object stateObj)
     {
+        // All list references are replaced — drop the entire view cache.
+        _unmodifiableSystemEventListeners = null;
         if (stateObj != null)
         {
             Map<Class<? extends SystemEvent>, Object> stateMap = (Map<Class<? extends SystemEvent>, Object>) stateObj;
-            _systemEventListenerClassMap = new HashMap<>(stateMap.size(), 1f);
+            _systemEventListeners = new HashMap<>(stateMap.size(), 1f);
             for (Map.Entry<Class<? extends SystemEvent>, Object> entry : stateMap.entrySet())
             {
-                _systemEventListenerClassMap.put(entry.getKey(),
+                _systemEventListeners.put(entry.getKey(),
                         (List<SystemEventListener>) restoreAttachedState(facesContext, entry.getValue()));
             }
         }
         else
         {
-            _systemEventListenerClassMap = null;
+            _systemEventListeners = null;
         }        
     }
     
@@ -2195,23 +2197,27 @@ private void restoreDeltaSystemEventListenerClassMap(FacesContext facesContext,
         if (stateObj != null)
         {
             Map<Class<? extends SystemEvent>, Object> stateMap = (Map<Class<? extends SystemEvent>, Object>) stateObj;
-            if (_systemEventListenerClassMap == null)
+            if (_systemEventListeners == null)
             {
-                _systemEventListenerClassMap = new HashMap<>(stateMap.size(), 1f);
+                _systemEventListeners = new HashMap<>(stateMap.size(), 1f);
             }
             for (Map.Entry<Class<? extends SystemEvent>, Object> entry : stateMap.entrySet())
             {
                 Object savedObject = entry.getValue(); 
                 if (savedObject instanceof _AttachedDeltaWrapper wrapper)
                 {
-                    StateHolder holderList = (StateHolder) _systemEventListenerClassMap.get(entry.getKey());
+                    // In-place delta restore: the existing list reference is kept, its contents
+                    // are mutated. The cached UnmodifiableList view delegates reads to the
+                    // backing list, so no cache invalidation is needed.
+                    StateHolder holderList = (StateHolder) _systemEventListeners.get(entry.getKey());
                     holderList.restoreState(facesContext,
                                             wrapper.getWrappedStateObject());
                 }
                 else
                 {
-                    _systemEventListenerClassMap.put(entry.getKey(),
+                    _systemEventListeners.put(entry.getKey(),
                             (List<SystemEventListener>) restoreAttachedState(facesContext, savedObject));
+                    _unmodifiableSystemEventListeners = null;
                 }
             }
         }
@@ -2219,15 +2225,15 @@ private void restoreDeltaSystemEventListenerClassMap(FacesContext facesContext,
     
     private Object saveSystemEventListenerClassMap(FacesContext facesContext)
     {
-        if (_systemEventListenerClassMap != null)
+        if (_systemEventListeners != null)
         {
             if (initialStateMarked())
             {
                 HashMap<Class<? extends SystemEvent>, Object> stateMap
-                        = new HashMap<>(_systemEventListenerClassMap.size(), 1);
+                        = new HashMap<>(_systemEventListeners.size(), 1);
                 boolean nullDelta = true;
                 for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener> > entry
-                        : _systemEventListenerClassMap.entrySet())
+                        : _systemEventListeners.entrySet())
                 {
                     // The list is always an instance of _DeltaList so we can cast to
                     // PartialStateHolder 
@@ -2238,7 +2244,7 @@ private Object saveSystemEventListenerClassMap(FacesContext facesContext)
                         if (attachedState != null)
                         {
                             stateMap.put(entry.getKey(),
-                                    new _AttachedDeltaWrapper(_systemEventListenerClassMap.getClass(), attachedState));
+                                    new _AttachedDeltaWrapper(_systemEventListeners.getClass(), attachedState));
                             nullDelta = false;
                         }
                     }
@@ -2258,9 +2264,9 @@ private Object saveSystemEventListenerClassMap(FacesContext facesContext)
             {
                 //Save it in the traditional way
                 HashMap<Class<? extends SystemEvent>, Object> stateMap = 
-                    new HashMap<>(_systemEventListenerClassMap.size(), 1);
+                    new HashMap<>(_systemEventListeners.size(), 1);
                 for (Map.Entry<Class<? extends SystemEvent>, List<SystemEventListener>> entry
-                        : _systemEventListenerClassMap.entrySet())
+                        : _systemEventListeners.entrySet())
                 {
                     stateMap.put(entry.getKey(), saveAttachedState(facesContext, entry.getValue()));
                 }