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()));
}