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/24 11:51:28 UTC

(myfaces) 02/02: [perf] optimize ELResolver impls

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

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

commit f2ba02f827fd3ef6b6cd95e8e2ad73bd54b9967a
Author: tandraschko <ta...@apache.org>
AuthorDate: Thu Jul 16 13:58:40 2026 +0200

    [perf] optimize ELResolver impls
    
    (cherry picked from commit b41d0d9f280a8650505daf90202351e834726d18)
---
 .../el/resolver/ResourceBundleResolver.java        | 18 +++++--
 .../el/resolver/ScopedAttributeResolver.java       | 59 ++++++++++++++++++++--
 2 files changed, 70 insertions(+), 7 deletions(-)

diff --git a/impl/src/main/java/org/apache/myfaces/el/resolver/ResourceBundleResolver.java b/impl/src/main/java/org/apache/myfaces/el/resolver/ResourceBundleResolver.java
index 29ccca2af..55418ba57 100644
--- a/impl/src/main/java/org/apache/myfaces/el/resolver/ResourceBundleResolver.java
+++ b/impl/src/main/java/org/apache/myfaces/el/resolver/ResourceBundleResolver.java
@@ -128,6 +128,13 @@ public Object getValue(final ELContext context, final Object base, final Object
         {
             return null;
         }
+        // fast path: when no <resource-bundle> var is configured in faces-config, this resolver can
+        // never resolve anything - skip the per-identifier Application.getResourceBundle/getBundleName
+        // chain that otherwise runs for every EL identifier (e.g. #{row} on every table cell).
+        if (runtimeConfig(context).getResourceBundles().isEmpty())
+        {
+            return null;
+        }
 
         final ResourceBundle bundle = getResourceBundle(context, (String)property);
         if (bundle != null)
@@ -155,6 +162,10 @@ public Class<?> getType(final ELContext context, final Object base, final Object
         {
             return null;
         }
+        if (runtimeConfig(context).getResourceBundles().isEmpty())
+        {
+            return null;
+        }
 
         final ResourceBundle bundle = getResourceBundle(context, (String)property);
         if (bundle != null)
@@ -217,12 +228,11 @@ private static ResourceBundle getResourceBundle(final ELContext context, final S
 
     protected RuntimeConfig runtimeConfig(ELContext context)
     {
-        final FacesContext facesContext = facesContext(context);
-
-        // application-level singleton - we can safely cache this
+        // application-level singleton - we can safely cache this (only resolve the FacesContext on
+        // the first call; this runs per EL identifier so avoid the lookup once cached)
         if (this.runtimeConfig == null)
         {
-            this.runtimeConfig = RuntimeConfig.getCurrentInstance(facesContext.getExternalContext());
+            this.runtimeConfig = RuntimeConfig.getCurrentInstance(facesContext(context).getExternalContext());
         }
 
         return runtimeConfig;
diff --git a/impl/src/main/java/org/apache/myfaces/el/resolver/ScopedAttributeResolver.java b/impl/src/main/java/org/apache/myfaces/el/resolver/ScopedAttributeResolver.java
index e5fc6f6ad..5e551d41b 100644
--- a/impl/src/main/java/org/apache/myfaces/el/resolver/ScopedAttributeResolver.java
+++ b/impl/src/main/java/org/apache/myfaces/el/resolver/ScopedAttributeResolver.java
@@ -104,10 +104,63 @@ public Object getValue(final ELContext context, final Object base, final Object
 
         context.setPropertyResolved(true);
 
-        final Map<String, Object> scopedMap = findScopedMap(facesContext(context), property);
-        if (scopedMap != null)
+        final FacesContext facesContext = facesContext(context);
+        if (facesContext == null)
+        {
+            return null;
+        }
+        final ExternalContext extContext = facesContext.getExternalContext();
+        if (extContext == null)
+        {
+            return null;
+        }
+
+        final boolean startup = (extContext instanceof StartupServletExternalContextImpl);
+
+        // A single get() per scope instead of findScopedMap()'s containsKey()+get(): servlet
+        // request/session/application attributes are never null, so a non-null get() means the key
+        // is present. This halves the attribute-map lookups for the very hot case of resolving a
+        // UIData/UIRepeat row var (e.g. #{row}) once per cell. Mirrors the reference
+        // ScopedAttributeELResolver. The view map is a plain Map that may legitimately hold a null
+        // value, so it keeps the containsKey() check.
+        Object value;
+
+        // request scope (not available at startup)
+        if (!startup)
+        {
+            value = extContext.getRequestMap().get(property);
+            if (value != null)
+            {
+                return value;
+            }
+        }
+
+        // jsf 2.0 view scope
+        UIViewRoot root = facesContext.getViewRoot();
+        if (root != null)
+        {
+            Map<String, Object> viewMap = root.getViewMap(false);
+            if (viewMap != null && viewMap.containsKey(property))
+            {
+                return viewMap.get(property);
+            }
+        }
+
+        // session scope (not available at startup)
+        if (!startup)
+        {
+            value = extContext.getSessionMap().get(property);
+            if (value != null)
+            {
+                return value;
+            }
+        }
+
+        // application scope
+        value = extContext.getApplicationMap().get(property);
+        if (value != null)
         {
-            return scopedMap.get(property);
+            return value;
         }
 
         return null;