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/07/07 13:08:28 UTC

(myfaces) branch 4.1.x updated (a20b54fa0 -> 5a0f9b0d0)

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

tandraschko pushed a change to branch 4.1.x
in repository https://gitbox.apache.org/repos/asf/myfaces.git


    from a20b54fa0 fixed regression reported by BalusC
     new 3fb301861 [perf] set collection size for StateHelper
     new 5a0f9b0d0 [perf] optimize APPLY_REQUEST_VALUES, PROCESS_VALIDATIONS, UPDATE_MODEL_VALUES cycles

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../jakarta/faces/component/UIComponentBase.java   | 127 ++++++++++++---------
 .../main/java/jakarta/faces/component/UIInput.java | 103 ++++++++---------
 .../jakarta/faces/component/_DeltaStateHelper.java |   8 +-
 .../component/behavior/_DeltaStateHelper.java      |   6 +-
 4 files changed, 132 insertions(+), 112 deletions(-)


(myfaces) 02/02: [perf] optimize APPLY_REQUEST_VALUES, PROCESS_VALIDATIONS, UPDATE_MODEL_VALUES cycles

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 5a0f9b0d0bf199919a93c393db013f337c11d9ec
Author: tandraschko <ta...@apache.org>
AuthorDate: Tue Jul 7 12:57:19 2026 +0200

    [perf] optimize APPLY_REQUEST_VALUES, PROCESS_VALIDATIONS, UPDATE_MODEL_VALUES cycles
    
    (cherry picked from commit 06d0131a692413cf69be9198f0ffdf0a918b3999)
---
 .../jakarta/faces/component/UIComponentBase.java   | 127 ++++++++++++---------
 .../main/java/jakarta/faces/component/UIInput.java | 103 ++++++++---------
 2 files changed, 125 insertions(+), 105 deletions(-)

diff --git a/api/src/main/java/jakarta/faces/component/UIComponentBase.java b/api/src/main/java/jakarta/faces/component/UIComponentBase.java
index fa0cc4559..56f177d70 100755
--- a/api/src/main/java/jakarta/faces/component/UIComponentBase.java
+++ b/api/src/main/java/jakarta/faces/component/UIComponentBase.java
@@ -1338,38 +1338,7 @@ public void processDecodes(FacesContext context)
             pushComponentToEL(context, this);
             if (_isPhaseExecutable(context))
             {
-                // Call the processDecodes() method of all facets and children of this UIComponent, in the order
-                // determined by a call to getFacetsAndChildren().
-                int facetCount = getFacetCount();
-                if (facetCount > 0)
-                {
-                    for (UIComponent facet : getFacets().values())
-                    {
-                        facet.processDecodes(context);
-                    }
-                }
-                if (getChildCount() > 0)
-                {
-                    List<UIComponent> children = getChildren();
-                    for (int i = 0; i < children.size(); i++)
-                    {
-                        UIComponent child = children.get(i);
-                        child.processDecodes(context);
-                    }
-                }
-
-                try
-                {
-                    // Call the decode() method of this component.
-                    decode(context);
-                }
-                catch (RuntimeException e)
-                {
-                    // If a RuntimeException is thrown during decode processing, call FacesContext.renderResponse()
-                    // and re-throw the exception.
-                    context.renderResponse();
-                    throw e;
-                }
+                _processDecodesChildrenAndSelf(context);
             }
         }
         finally
@@ -1382,6 +1351,49 @@ public void processDecodes(FacesContext context)
         }
     }
 
+    /**
+     * Decodes all facets/children of this component followed by this component itself (the part of
+     * processDecodes() that runs once rendered == true has already been established). Factored out of
+     * processDecodes() so subclasses that need to combine it with extra per-phase logic (e.g. UIInput's
+     * "immediate" validation) can do so within a single pushComponentToEL()/popComponentFromEL() cycle
+     * instead of the caller having to enter/leave the EL component stack an extra time.
+     */
+    void _processDecodesChildrenAndSelf(FacesContext context)
+    {
+        // Call the processDecodes() method of all facets and children of this UIComponent, in the order
+        // determined by a call to getFacetsAndChildren().
+        int facetCount = getFacetCount();
+        if (facetCount > 0)
+        {
+            for (UIComponent facet : getFacets().values())
+            {
+                facet.processDecodes(context);
+            }
+        }
+        if (getChildCount() > 0)
+        {
+            List<UIComponent> children = getChildren();
+            for (int i = 0; i < children.size(); i++)
+            {
+                UIComponent child = children.get(i);
+                child.processDecodes(context);
+            }
+        }
+
+        try
+        {
+            // Call the decode() method of this component.
+            decode(context);
+        }
+        catch (RuntimeException e)
+        {
+            // If a RuntimeException is thrown during decode processing, call FacesContext.renderResponse()
+            // and re-throw the exception.
+            context.renderResponse();
+            throw e;
+        }
+    }
+
     @Override
     public void processValidators(FacesContext context)
     {
@@ -1449,26 +1461,7 @@ public void processUpdates(FacesContext context)
             pushComponentToEL(context, this);
             if (_isPhaseExecutable(context))
             {
-                // Call the processUpdates() method of all facets and children of this UIComponent, in the order
-                // determined by a call to getFacetsAndChildren().
-                int facetCount = getFacetCount();
-                if (facetCount > 0)
-                {
-                    for (UIComponent facet : getFacets().values())
-                    {
-                        facet.processUpdates(context);
-                    }
-                }
-
-                if (getChildCount() > 0)
-                {
-                    List<UIComponent> children = getChildren();
-                    for (int i = 0; i < children.size(); i++)
-                    {
-                        UIComponent child = children.get(i);
-                        child.processUpdates(context);
-                    }
-                }
+                _processUpdatesChildren(context);
             }
         }
         finally
@@ -1481,6 +1474,36 @@ public void processUpdates(FacesContext context)
         }
     }
 
+    /**
+     * Calls processUpdates() on all facets/children of this component (the part of processUpdates() that
+     * runs once rendered == true has already been established). Factored out for the same reason as
+     * {@link #_processDecodesChildrenAndSelf(FacesContext)} - so UIInput can fold this into a single
+     * pushComponentToEL()/popComponentFromEL() cycle together with its own updateModel() call.
+     */
+    void _processUpdatesChildren(FacesContext context)
+    {
+        // Call the processUpdates() method of all facets and children of this UIComponent, in the order
+        // determined by a call to getFacetsAndChildren().
+        int facetCount = getFacetCount();
+        if (facetCount > 0)
+        {
+            for (UIComponent facet : getFacets().values())
+            {
+                facet.processUpdates(context);
+            }
+        }
+
+        if (getChildCount() > 0)
+        {
+            List<UIComponent> children = getChildren();
+            for (int i = 0; i < children.size(); i++)
+            {
+                UIComponent child = children.get(i);
+                child.processUpdates(context);
+            }
+        }
+    }
+
     @Override
     public Object processSaveState(FacesContext context)
     {
diff --git a/api/src/main/java/jakarta/faces/component/UIInput.java b/api/src/main/java/jakarta/faces/component/UIInput.java
index 3d1397cc0..f0ace5047 100644
--- a/api/src/main/java/jakarta/faces/component/UIInput.java
+++ b/api/src/main/java/jakarta/faces/component/UIInput.java
@@ -197,27 +197,23 @@ public void processDecodes(FacesContext context)
     {
         Assert.notNull(context, "context");
 
+        // perf: do the "rendered" check, the decode of this component/its children and the "immediate"
+        // validation within a single pushComponentToEL()/popComponentFromEL() cycle (and a single
+        // isRendered() evaluation) instead of the three separate cycles used previously - each cycle costs
+        // a FacesContext attribute map lookup plus a List push/pop, and this method runs once per input
+        // component per request.
         try
         {
             setCachedFacesContext(context);
             pushComponentToEL(context, this);
+
             if (!isRendered())
             {
                 return;
             }
-        }
-        finally
-        {
-            setCachedFacesContext(null);
-            popComponentFromEL(context);
-        }
 
-        super.processDecodes(context);
+            _processDecodesChildrenAndSelf(context);
 
-        try
-        {
-            setCachedFacesContext(context);
-            pushComponentToEL(context, this);
             if (isImmediate())
             {
                 //Pre validation event dispatch for component
@@ -253,46 +249,40 @@ public void processDecodes(FacesContext context)
     public void processValidators(FacesContext context)
     {
         Assert.notNull(context, "context");
-        
+
+        // perf: see the comment in processDecodes() - fold the "rendered" check, the recursive
+        // processValidators() of facets/children and the immediate-validation of this component into a
+        // single push/pop cycle instead of two.
         try
         {
             setCachedFacesContext(context);
             pushComponentToEL(context, this);
+
             if (!isRendered())
             {
                 return;
             }
-        }
-        finally
-        {
-            setCachedFacesContext(null);
-            popComponentFromEL(context);
-        }
-        
-        // Call the processValidators() method of all facets and children of this UIComponent, in the order
-        // determined by a call to getFacetsAndChildren().
-        if (getFacetCount() > 0)
-        {
-            for (UIComponent facet : getFacets().values())
+
+            // Call the processValidators() method of all facets and children of this UIComponent, in the
+            // order determined by a call to getFacetsAndChildren().
+            if (getFacetCount() > 0)
             {
-                facet.processValidators(context);
+                for (UIComponent facet : getFacets().values())
+                {
+                    facet.processValidators(context);
+                }
             }
-        }
 
-        int childCount = getChildCount();
-        if (childCount > 0)
-        {
-            List<UIComponent> children = getChildren();
-            for (int i = 0; i < childCount; i++)
+            int childCount = getChildCount();
+            if (childCount > 0)
             {
-                children.get(i).processValidators(context);
+                List<UIComponent> children = getChildren();
+                for (int i = 0; i < childCount; i++)
+                {
+                    children.get(i).processValidators(context);
+                }
             }
-        }
 
-        try
-        {
-            setCachedFacesContext(context);
-            pushComponentToEL(context, this);
             if (!isImmediate())
             {
                 //Pre validation event dispatch for component
@@ -330,27 +320,20 @@ public void processUpdates(FacesContext context)
     {
         Assert.notNull(context, "context");
 
+        // perf: see the comment in processDecodes() - fold the "rendered" check, the recursive
+        // processUpdates() of children and the updateModel() call into a single push/pop cycle.
         try
         {
             setCachedFacesContext(context);
             pushComponentToEL(context, this);
+
             if (!isRendered())
             {
                 return;
             }
-        }
-        finally
-        {
-            setCachedFacesContext(null);
-            popComponentFromEL(context);
-        }
 
-        super.processUpdates(context);
+            _processUpdatesChildren(context);
 
-        try
-        {
-            setCachedFacesContext(context);
-            pushComponentToEL(context, this);
             try
             {
                 updateModel(context);
@@ -732,12 +715,26 @@ public void validate(FacesContext context)
             return;
         }
 
-        Object previousValue = getValue();
-        setValue(convertedValue);
-        setSubmittedValue(null);
-        if (compareValues(previousValue, convertedValue))
+        // perf: only fetch the previous value (a "value" binding read, which for an EL
+        // expression like #{row.name} means a full ELResolver chain round trip - can be
+        // expensive, e.g. when a CDI implementation is part of the chain) and run
+        // compareValues() when there is at least one ValueChangeListener that could
+        // possibly care about the resulting event; queueEvent() would otherwise just be
+        // discarded (silently, since nothing is registered to receive it) at broadcast time.
+        if (getFacesListeners(ValueChangeListener.class).length == 0)
         {
-            queueEvent(new ValueChangeEvent(this, previousValue, convertedValue));
+            setValue(convertedValue);
+            setSubmittedValue(null);
+        }
+        else
+        {
+            Object previousValue = getValue();
+            setValue(convertedValue);
+            setSubmittedValue(null);
+            if (compareValues(previousValue, convertedValue))
+            {
+                queueEvent(new ValueChangeEvent(this, previousValue, convertedValue));
+            }
         }
     }
 


(myfaces) 01/02: [perf] set collection size for StateHelper

Posted by ta...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 3fb30186125fb25f2109af4b7fd46600f8ad95c7
Author: tandraschko <ta...@apache.org>
AuthorDate: Thu Jul 2 17:47:36 2026 +0200

    [perf] set collection size for StateHelper
---
 api/src/main/java/jakarta/faces/component/_DeltaStateHelper.java  | 8 ++++----
 .../java/jakarta/faces/component/behavior/_DeltaStateHelper.java  | 6 +++---
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/api/src/main/java/jakarta/faces/component/_DeltaStateHelper.java b/api/src/main/java/jakarta/faces/component/_DeltaStateHelper.java
index 996de292e..5c44c6a3d 100644
--- a/api/src/main/java/jakarta/faces/component/_DeltaStateHelper.java
+++ b/api/src/main/java/jakarta/faces/component/_DeltaStateHelper.java
@@ -193,7 +193,7 @@ private Map<Serializable, Object> _ensureFullState()
     {
         if (_fullState == null)
         {
-            _fullState = new HashMap<>();
+            _fullState = new HashMap<>(8, 1f);
         }
         return _fullState;
     }
@@ -247,7 +247,7 @@ private boolean _createDeltas(Serializable key)
             }
             if (_deltas == null)
             {
-                _deltas = new HashMap<>();
+                _deltas = new HashMap<>(4, 1f);
             }
             return true;
         }
@@ -433,7 +433,7 @@ public Object put(Serializable key, String mapKey, Object value)
             Map<String, Object> mapValues = (Map<String, Object>) _deltas.get(key);
             if (mapValues == null)
             {
-                mapValues = new InternalMap<>();
+                mapValues = new InternalMap<>(4, 1f);
                 _deltas.put(key, mapValues);
             }
 
@@ -452,7 +452,7 @@ public Object put(Serializable key, String mapKey, Object value)
         Map<String, Object> mapValues = _fullState != null ? (Map<String, Object>) _fullState.get(key) : null;
         if (mapValues == null)
         {
-            mapValues = new InternalMap<>();
+            mapValues = new InternalMap<>(4, 1f);
             _ensureFullState().put(key, mapValues);
         }
 
diff --git a/api/src/main/java/jakarta/faces/component/behavior/_DeltaStateHelper.java b/api/src/main/java/jakarta/faces/component/behavior/_DeltaStateHelper.java
index a9e1909ac..68d693ced 100644
--- a/api/src/main/java/jakarta/faces/component/behavior/_DeltaStateHelper.java
+++ b/api/src/main/java/jakarta/faces/component/behavior/_DeltaStateHelper.java
@@ -170,7 +170,7 @@ private Map<Serializable, Object> _ensureFullState()
     {
         if (_fullState == null)
         {
-            _fullState = new HashMap<>();
+            _fullState = new HashMap<>(8, 1f);
         }
         return _fullState;
     }
@@ -335,7 +335,7 @@ public Object put(Serializable key, String mapKey, Object value)
             Map<String, Object> mapValues = (Map<String, Object>) _deltas.get(key);
             if (mapValues == null)
             {
-                mapValues = new InternalMap<>();
+                mapValues = new InternalMap<>(4, 1f);
                 _deltas.put(key, mapValues);
             }
 
@@ -354,7 +354,7 @@ public Object put(Serializable key, String mapKey, Object value)
         Map<String, Object> mapValues = _fullState != null ? (Map<String, Object>) _fullState.get(key) : null;
         if (mapValues == null)
         {
-            mapValues = new InternalMap<>();
+            mapValues = new InternalMap<>(4, 1f);
             _ensureFullState().put(key, mapValues);
         }