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 21:11:50 UTC

(myfaces) branch main updated: [perf] improve initial collection size

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 6f38195d9 [perf] improve initial collection size
6f38195d9 is described below

commit 6f38195d980c12051f6e4d5318bc423b3640f58e
Author: tandraschko <ta...@apache.org>
AuthorDate: Tue Jul 7 23:11:38 2026 +0200

    [perf] improve initial collection size
---
 .../myfaces/application/ApplicationImpl.java       | 25 +++++++++++++++-------
 .../application/FacesServletMappingUtils.java      | 14 ++++++------
 .../myfaces/application/NavigationHandlerImpl.java | 11 ++++++----
 .../myfaces/application/TreeStructureManager.java  |  7 +++---
 .../context/servlet/RequestHeaderValuesMap.java    |  6 +++++-
 .../servlet/ServletExternalContextImpl.java        | 15 +++++++++----
 .../apache/myfaces/lifecycle/LifecycleImpl.java    |  6 +++++-
 7 files changed, 56 insertions(+), 28 deletions(-)

diff --git a/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java b/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
index 0eac5d3f8..2e93e523d 100755
--- a/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
@@ -167,6 +167,8 @@ public class ApplicationImpl extends Application
     private StateManager _stateManager;
     private FlowHandler _flowHandler;
 
+    private static final ELContextListener[] EMPTY_EL_CONTEXT_LISTENERS = new ELContextListener[0];
+
     private ArrayList<ELContextListener> _elContextListeners;
 
     // components, converters, and validators can be added at runtime--must
@@ -552,7 +554,9 @@ public final ELContextListener[] getELContextListeners()
         // this gets called on every request, so I can't afford to synchronize
         // I just have to trust that toArray() with do the right thing if the
         // list is changing (not likely)
-        return _elContextListeners.toArray(new ELContextListener[_elContextListeners.size()]);
+        return _elContextListeners.isEmpty()
+                ? EMPTY_EL_CONTEXT_LISTENERS
+                : _elContextListeners.toArray(new ELContextListener[_elContextListeners.size()]);
     }
 
     @Override
@@ -1680,15 +1684,17 @@ private void _handleAttachedResourceDependencyAnnotations(FacesContext context,
         List<ResourceDependency> dependencyList = _classToResourceDependencyMap.get(inspectedClass);
         if (dependencyList == null)
         {
-            dependencyList = new ArrayList<>(5);
-
             ResourceDependency dependency = inspectedClass.getAnnotation(ResourceDependency.class);
+            ResourceDependencies dependencies = inspectedClass.getAnnotation(ResourceDependencies.class);
+
+            dependencyList = new ArrayList<>((dependency != null ? 1 : 0)
+                    + (dependencies != null ? dependencies.value().length : 0));
+
             if (dependency != null)
             {
                 dependencyList.add(dependency);
             }
 
-            ResourceDependencies dependencies = inspectedClass.getAnnotation(ResourceDependencies.class);
             if (dependencies != null)
             {
                 dependencyList.addAll(Arrays.asList(dependencies.value()));
@@ -2012,15 +2018,17 @@ private void _handleListenerForAnnotations(FacesContext context, Object inspecte
         List<ListenerFor> listenerForList = _classToListenerForMap.get(inspectedClass);
         if (listenerForList == null)
         {
-            listenerForList = new ArrayList<>(5);
-
             ListenerFor listener = inspectedClass.getAnnotation(ListenerFor.class);
+            ListenersFor listeners = inspectedClass.getAnnotation(ListenersFor.class);
+
+            listenerForList = new ArrayList<>((listener != null ? 1 : 0)
+                    + (listeners != null ? listeners.value().length : 0));
+
             if (listener != null)
             {
                 listenerForList.add(listener);
             }
 
-            ListenersFor listeners = inspectedClass.getAnnotation(ListenersFor.class);
             if (listeners != null)
             {
                 listenerForList.addAll(Arrays.asList(listeners.value()));
@@ -2147,7 +2155,8 @@ private void _handleResourceDependencyAnnotations(FacesContext context, Class<?>
             if(dependency != null || dependencies != null)
             {
                 //resource dependencies were found using one or both annotations, create and build a new list
-                dependencyList = new ArrayList<>();
+                dependencyList = new ArrayList<>((dependency != null ? 1 : 0)
+                        + (dependencies != null ? dependencies.value().length : 0));
                 
                 if(dependency != null)
                 {
diff --git a/impl/src/main/java/org/apache/myfaces/application/FacesServletMappingUtils.java b/impl/src/main/java/org/apache/myfaces/application/FacesServletMappingUtils.java
index e39666398..7353fdd54 100644
--- a/impl/src/main/java/org/apache/myfaces/application/FacesServletMappingUtils.java
+++ b/impl/src/main/java/org/apache/myfaces/application/FacesServletMappingUtils.java
@@ -40,6 +40,8 @@ public class FacesServletMappingUtils
     private static final String SERVLET_REGISTRATIONS = "org.apache.myfaces.SERVLET_REGISTRATIONS";
     
     private static final String CURRENT_REQUEST_FACES_SERVLET = "org.apache.myfaces.CURRENT_FACES_SERVLET_MAPPING";
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
     
     /**
      * Wrapper for better performance
@@ -58,11 +60,9 @@ public ServletRegistrationInfo(ServletRegistration registration, boolean facesSe
             this.registration = registration;
 
             Collection<String> mappingsCollection = registration.getMappings();
-            mappings = mappingsCollection.toArray(new String[mappingsCollection.size()]);
-            if (mappings == null)
-            {
-                mappings = new String[]{ };
-            }
+            mappings = mappingsCollection.isEmpty()
+                    ? EMPTY_STRING_ARRAY
+                    : mappingsCollection.toArray(new String[mappingsCollection.size()]);
         }
 
         public String getClassName()
@@ -115,9 +115,9 @@ public static List<ServletRegistrationInfo> getServletRegistrations(FacesContext
                 (List<ServletRegistrationInfo>) applicationMap.get(SERVLET_REGISTRATIONS);
         if (infos == null)
         {
-            infos = new ArrayList<>();
-            
             Map<String, ? extends ServletRegistration> registrations = servletContext.getServletRegistrations();
+            infos = new ArrayList<>(registrations != null ? registrations.size() : 0);
+
             if (registrations != null)
             {
                 for (ServletRegistration servletRegistration : registrations.values())
diff --git a/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java b/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java
index 7b86dfcac..426159e6e 100755
--- a/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java
@@ -186,7 +186,7 @@ else if (fromViewId != null && !fromViewId.equals(toViewId))
                         // MYFACES-4504: check isEmpty()
                         if (navigationCaseParameters == null || navigationCaseParameters.isEmpty())
                         {
-                            navigationCaseParameters = new HashMap<>(5, 1f);
+                            navigationCaseParameters = new HashMap<>(3, 1f);
                         }
                         
                         // If current flow (sourceFlow) is not null and new flow (targetFlow) is null,
@@ -1156,7 +1156,8 @@ private NavigationCase getOutcomeNavigationCase(FacesContext facesContext, Strin
                         List<String> paramValues = params.get(splitParam[0]);
                         if (paramValues == null)
                         {
-                            paramValues = new ArrayList<>(5);
+                            // most parameters only occur once; grows automatically for repeated names
+                            paramValues = new ArrayList<>(1);
                             params.put(splitParam[0], paramValues);
                         }
                         paramValues.add(splitParam[1]);
@@ -1406,7 +1407,8 @@ public void inspectFlow(FacesContext context, Flow flow)
 
         Map<String, Set<NavigationCase>> cases = new HashMap<>(HashMapUtils.calcCapacity(rulesSize));
 
-        List<_WildcardPattern> wildcardPatterns = new ArrayList<>();
+        // at most one wildcard pattern is added per distinct fromViewId, bounded by rulesSize
+        List<_WildcardPattern> wildcardPatterns = new ArrayList<>(rulesSize);
 
         for (Map.Entry<String, Set<NavigationCase>> entry : rules.entrySet())
         {
@@ -1454,7 +1456,8 @@ private synchronized void calculateNavigationCases(RuntimeConfig runtimeConfig)
 
             Map<String, Set<NavigationCase>> cases = new HashMap<>(HashMapUtils.calcCapacity(rulesSize));
 
-            List<_WildcardPattern> wildcardPatterns = new ArrayList<>();
+            // at most one wildcard pattern is added per distinct fromViewId, bounded by rulesSize
+            List<_WildcardPattern> wildcardPatterns = new ArrayList<>(rulesSize);
             for (NavigationRule rule : rules)
             {
                 String fromViewId = rule.getFromViewId();
diff --git a/impl/src/main/java/org/apache/myfaces/application/TreeStructureManager.java b/impl/src/main/java/org/apache/myfaces/application/TreeStructureManager.java
index 052eb64d8..419c43075 100755
--- a/impl/src/main/java/org/apache/myfaces/application/TreeStructureManager.java
+++ b/impl/src/main/java/org/apache/myfaces/application/TreeStructureManager.java
@@ -54,7 +54,7 @@ private static TreeStructComponent internalBuildTreeStructureToSave(UIComponent
         if (childCount > 0)
         {
             List<UIComponent> children = component.getChildren();
-            List<TreeStructComponent> structChildList = new ArrayList<>();
+            List<TreeStructComponent> structChildList = new ArrayList<>(childCount);
             for (int i = 0; i < childCount; i++)
             {
                 UIComponent child = children.get(i);
@@ -71,10 +71,11 @@ private static TreeStructComponent internalBuildTreeStructureToSave(UIComponent
         }
 
         //facets
-        if (component.getFacetCount() > 0)
+        int facetCount = component.getFacetCount();
+        if (facetCount > 0)
         {
             Map<String, UIComponent> facetMap = component.getFacets();
-            List<Object[]> structFacetList = new ArrayList<>();
+            List<Object[]> structFacetList = new ArrayList<>(facetCount);
             for (Map.Entry<String, UIComponent> entry : facetMap.entrySet())
             {
                 UIComponent child = entry.getValue();
diff --git a/impl/src/main/java/org/apache/myfaces/context/servlet/RequestHeaderValuesMap.java b/impl/src/main/java/org/apache/myfaces/context/servlet/RequestHeaderValuesMap.java
index dbcf6c7fb..0c936ad94 100755
--- a/impl/src/main/java/org/apache/myfaces/context/servlet/RequestHeaderValuesMap.java
+++ b/impl/src/main/java/org/apache/myfaces/context/servlet/RequestHeaderValuesMap.java
@@ -36,6 +36,8 @@
  */
 public final class RequestHeaderValuesMap extends AbstractAttributeMap<String[]>
 {
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
     private final HttpServletRequest httpServletRequest;
     private final Map<String, String[]> attributeValueCache = new HashMap<>();
 
@@ -52,7 +54,9 @@ protected String[] getAttribute(final String key)
         {
             List<String> attributesList = Collections.list(httpServletRequest.getHeaders(key));
 
-            attributes = attributesList.toArray(new String[attributesList.size()]);
+            attributes = attributesList.isEmpty()
+                    ? EMPTY_STRING_ARRAY
+                    : attributesList.toArray(new String[attributesList.size()]);
             attributeValueCache.put(key, attributes);
         }
 
diff --git a/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java b/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java
index 67075ff8a..2de1e56ad 100755
--- a/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java
@@ -891,7 +891,9 @@ private String encodeURL(String baseUrl, Map<String, List<String>> parameters)
 
                 if (paramMap == null)
                 {
-                    paramMap = new HashMap<>(5, 1f);
+                    // nameValuePairs.length is an upper bound on the number of distinct
+                    // parameter names (duplicates just mean fewer), so it never resizes
+                    paramMap = new HashMap<>(nameValuePairs.length, 1f);
                 }
 
                 List<String> values = paramMap.get(currentName);
@@ -926,7 +928,9 @@ private String encodeURL(String baseUrl, Map<String, List<String>> parameters)
                 {
                     if (paramMap == null)
                     {
-                        paramMap = new HashMap<>(5, 1f);
+                        // parameters.size() is an upper bound on the number of entries
+                        // that will be put into paramMap in this loop
+                        paramMap = new HashMap<>(parameters.size(), 1f);
                     }
                     paramMap.put(key, pair.getValue());
                 }
@@ -937,9 +941,13 @@ private String encodeURL(String baseUrl, Map<String, List<String>> parameters)
         ClientWindow window = facesContext.getExternalContext().getClientWindow();
         if (window != null && window.isClientWindowRenderModeEnabled(facesContext))
         {
+            Map<String, String> additionalQueryURLParameters = window.getQueryURLParameters(facesContext);
+
             if (paramMap == null)
             {
-                paramMap = new HashMap<>(5, 1f);
+                // upper bound: the client window id param plus any additional query params
+                paramMap = new HashMap<>(1 + (additionalQueryURLParameters != null
+                        ? additionalQueryURLParameters.size() : 0), 1f);
             }
 
             if (!paramMap.containsKey(ResponseStateManager.CLIENT_WINDOW_URL_PARAM))
@@ -947,7 +955,6 @@ private String encodeURL(String baseUrl, Map<String, List<String>> parameters)
                 paramMap.put(ResponseStateManager.CLIENT_WINDOW_URL_PARAM, Arrays.asList(window.getId()));
             }
 
-            Map<String, String> additionalQueryURLParameters = window.getQueryURLParameters(facesContext);
             if (additionalQueryURLParameters != null)
             {
                 for (Map.Entry<String , String> entry : additionalQueryURLParameters.entrySet())
diff --git a/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java b/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java
index c2e106197..f3b2be48d 100755
--- a/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java
@@ -52,6 +52,8 @@
 public class LifecycleImpl extends Lifecycle
 {
     private static final Logger log = Logger.getLogger(LifecycleImpl.class.getName());
+
+    private static final PhaseListener[] EMPTY_PHASE_LISTENERS = new PhaseListener[0];
     
     /**
      * Boolean.TRUE is stored under this key in the application map if
@@ -346,7 +348,9 @@ public void removePhaseListener(PhaseListener phaseListener)
     @Override
     public PhaseListener[] getPhaseListeners()
     {
-        return phaseListeners.toArray(new PhaseListener[phaseListeners.size()]);
+        return phaseListeners.isEmpty()
+                ? EMPTY_PHASE_LISTENERS
+                : phaseListeners.toArray(new PhaseListener[phaseListeners.size()]);
     }
     
     private void publishException(Throwable e, PhaseId phaseId, FacesContext facesContext)