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 07:30:30 UTC

(myfaces) 01/02: [perf] cache parent UINamingContainer

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

commit b151ff00654c0151091e6100980019f004b0240c
Author: tandraschko <ta...@apache.org>
AuthorDate: Tue Jun 2 17:27:53 2026 +0200

    [perf] cache parent UINamingContainer
---
 .../jakarta/faces/component/UIComponentBase.java   | 30 ++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/api/src/main/java/jakarta/faces/component/UIComponentBase.java b/api/src/main/java/jakarta/faces/component/UIComponentBase.java
index 0d989515e..e73fcb2ab 100755
--- a/api/src/main/java/jakarta/faces/component/UIComponentBase.java
+++ b/api/src/main/java/jakarta/faces/component/UIComponentBase.java
@@ -99,6 +99,8 @@ public abstract class UIComponentBase extends UIComponent
     private UIComponent _parent = null;
     private boolean _transient = false;
 
+    private transient UIComponent _closestNamingContainer;
+
     private String _rendererType;
     private String _markCreated;
     private String _facetName;
@@ -170,6 +172,11 @@ public void setId(String id)
     @Override
     public void setParent(UIComponent parent)
     {
+        // The parent chain is changing — the cached NamingContainer ancestor is no longer valid.
+        // setId must NOT clear it: UIData/UIRepeat call setId(getId()) per row on every descendant,
+        // and the ancestor depends only on the parent chain which setId never changes.
+        _closestNamingContainer = null;
+
         // removing kids OR this is UIViewRoot
         if (parent == null)
         {
@@ -906,7 +913,7 @@ public String getClientId(FacesContext context)
             setId(id);
         }
 
-        UIComponent namingContainer = ComponentUtils.findClosestNamingContainer(this, false);
+        UIComponent namingContainer = getClosestNamingContainer();
         if (namingContainer != null)
         {
             String containerClientId = namingContainer.getContainerClientId(context);
@@ -947,7 +954,26 @@ public String getClientId(FacesContext context)
 
         return _clientId;
     }
-    
+
+    /**
+     * Returns the closest NamingContainer ancestor, caching the result so that repeated calls
+     * (e.g. once per UIRepeat/UIData row after setId clears _clientId) skip the parent-chain walk.
+     * Invalidated in setParent only — setId must NOT clear it.
+     */
+    private UIComponent getClosestNamingContainer()
+    {
+        if (_closestNamingContainer != null)
+        {
+            return _closestNamingContainer;
+        }
+        UIComponent closestNamingContainer = ComponentUtils.findClosestNamingContainer(this, false);
+        if (closestNamingContainer != null)
+        {
+            _closestNamingContainer = closestNamingContainer;
+        }
+        return closestNamingContainer;
+    }
+
     /**
      * 
      * @return