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/openwebbeans.git


The following commit(s) were added to refs/heads/main by this push:
     new 593e02b34 OWB-1456 - [perf] optimize 
configureProducerMethodSpecializations
593e02b34 is described below

commit 593e02b34e08e8f32a397f6522a9b33cd31391d6
Author: tandraschko <[email protected]>
AuthorDate: Tue Apr 14 16:53:04 2026 +0200

    OWB-1456 - [perf] optimize configureProducerMethodSpecializations
---
 .../org/apache/webbeans/config/BeansDeployer.java  |  81 +++++++++-------
 .../ProducerMethodSpecializationOverloadTest.java  | 106 +++++++++++++++++++++
 2 files changed, 151 insertions(+), 36 deletions(-)

diff --git 
a/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java 
b/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java
index bde8afaac..1b9f88d85 100644
--- a/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java
+++ b/webbeans-impl/src/main/java/org/apache/webbeans/config/BeansDeployer.java
@@ -117,6 +117,7 @@ import java.lang.reflect.Type;
 import java.net.URL;
 import java.security.PrivilegedActionException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -129,8 +130,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
 import static java.util.Arrays.asList;
 import static org.apache.webbeans.spi.BeanArchiveService.BeanDiscoveryMode;
 import static 
org.apache.webbeans.spi.BeanArchiveService.BeanArchiveInformation;
@@ -1047,53 +1046,63 @@ public class BeansDeployer
     {
         Set<Bean<?>> beans = webBeansContext.getBeanManagerImpl().getBeans();
 
-        // Collect all producer method beans
-        // and sort them with subclasses first
-        // This is important as we can later go top-down and
-        // disable all 'overwritten' producer methods which must be
-        // further down in the list
-        List<ProducerMethodBean> producerMethodBeans = beans.stream()
-            .filter(ProducerMethodBean.class::isInstance)
-            .map(ProducerMethodBean.class::cast)
-            .collect(Collectors.toList());
-
-        checkSpecializedProducerMethodConditions(producerMethodBeans);
-
-        for (int i = 0; i < producerMethodBeans.size(); i++)
+        List<ProducerMethodBean<?>> producerMethodBeans = new ArrayList<>();
+        Map<String, List<ProducerMethodBean<?>>> byCreatorMethodName = new 
HashMap<>();
+        for (Bean<?> bean : beans)
         {
-            ProducerMethodBean<?> producerMethodBean = 
producerMethodBeans.get(i);
-            if (!producerMethodBean.isEnabled())
+            if (!(bean instanceof ProducerMethodBean))
             {
                 continue;
             }
+            ProducerMethodBean<?> pmb = (ProducerMethodBean<?>) bean;
+            producerMethodBeans.add(pmb);
+            byCreatorMethodName
+                    .computeIfAbsent(pmb.getCreatorMethod().getName(), k -> 
new ArrayList<>())
+                    .add(pmb);
+        }
 
-            for (int j = 0; j < producerMethodBeans.size(); j++)
-            {
-                ProducerMethodBean<?> otherProducerMethodBean = 
producerMethodBeans.get(j);
+        checkSpecializedProducerMethodConditions(producerMethodBeans);
 
-                if (i==j)
+        // Only producers sharing the same Java method name can specialize 
each other; compare within
+        // those buckets (not full n² over all producer methods). Disabling 
still requires the same
+        // erased parameter types as overriding / CDI producer specialization 
(so unrelated overloads stay).
+        for (List<ProducerMethodBean<?>> sameName : 
byCreatorMethodName.values())
+        {
+            int size = sameName.size();
+            for (int i = 0; i < size; i++)
+            {
+                ProducerMethodBean<?> producerMethodBean = sameName.get(i);
+                if (!producerMethodBean.isEnabled())
                 {
-                    // makes no sense to compare with ourselves
                     continue;
                 }
 
-                if (!otherProducerMethodBean.isEnabled())
+                for (int j = 0; j < size; j++)
                 {
-                    // already disabled
-                    continue;
-                }
+                    ProducerMethodBean<?> otherProducerMethodBean = 
sameName.get(j);
 
-                if 
(producerMethodBean.getBeanClass().equals(otherProducerMethodBean.getBeanClass()))
-                {
-                    // must be another producerMethod from the same class. 
Probably different qualifier?
-                    continue;
-                }
+                    if (i == j)
+                    {
+                        // makes no sense to compare with ourselves
+                        continue;
+                    }
 
-                if 
(otherProducerMethodBean.getBeanClass().isAssignableFrom(producerMethodBean.getBeanClass()))
-                {
-                    // yikes we did hit a superclass!
+                    if (!otherProducerMethodBean.isEnabled())
+                    {
+                        // already disabled
+                        continue;
+                    }
+
+                    if 
(producerMethodBean.getBeanClass().equals(otherProducerMethodBean.getBeanClass()))
+                    {
+                        // must be another producerMethod from the same class. 
Probably different qualifier?
+                        continue;
+                    }
 
-                    if 
(producerMethodBean.getCreatorMethod().getName().equals(otherProducerMethodBean.getCreatorMethod().getName()))
+                    if 
(otherProducerMethodBean.getBeanClass().isAssignableFrom(producerMethodBean.getBeanClass())
+                            && Arrays.equals(
+                                    
producerMethodBean.getCreatorMethod().getParameterTypes(),
+                                    
otherProducerMethodBean.getCreatorMethod().getParameterTypes()))
                     {
                         // disable the other bean as it got 'specialized' with 
the current bean.
                         otherProducerMethodBean.setEnabled(false);
@@ -1107,7 +1116,7 @@ public class BeansDeployer
      * Verify that all conditions for Specialized producer methdods are met.
      * See spec section 3.3.3. Specializing a producer method
      */
-    private void 
checkSpecializedProducerMethodConditions(List<ProducerMethodBean> producerBeans)
+    private void 
checkSpecializedProducerMethodConditions(List<ProducerMethodBean<?>> 
producerBeans)
     {
         Set<String> methodsDisabledDueToSpecialization = new HashSet<>();
         for (ProducerMethodBean producerBean : producerBeans)
diff --git 
a/webbeans-impl/src/test/java/org/apache/webbeans/test/specalization/ProducerMethodSpecializationOverloadTest.java
 
b/webbeans-impl/src/test/java/org/apache/webbeans/test/specalization/ProducerMethodSpecializationOverloadTest.java
new file mode 100644
index 000000000..642c8c155
--- /dev/null
+++ 
b/webbeans-impl/src/test/java/org/apache/webbeans/test/specalization/ProducerMethodSpecializationOverloadTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.webbeans.test.specalization;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Set;
+
+import jakarta.enterprise.inject.Produces;
+import jakarta.enterprise.inject.Specializes;
+import jakarta.enterprise.inject.spi.Bean;
+import jakarta.enterprise.util.AnnotationLiteral;
+import jakarta.inject.Qualifier;
+
+import org.apache.webbeans.test.AbstractUnitTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * A subclass {@code @Specializes} producer must not disable a superclass 
producer that only shares
+ * the same Java method name but has a different parameter list (CDI 3.3.3 / 
Java overriding).
+ */
+public class ProducerMethodSpecializationOverloadTest extends AbstractUnitTest
+{
+    @Test
+    public void testSpecializingNoArgDoesNotDisableParameterOverload()
+    {
+        startContainer(BaseOverload.class, SubSpecializesNoArgOnly.class, 
ProducerDep.class);
+
+        Set<Bean<?>> noArg = getBeanManager().getBeans(String.class, new 
AnnotationLiteral<QNoArg>()
+        {
+        });
+        Assert.assertEquals(1, noArg.size());
+
+        Set<Bean<?>> depOverload = getBeanManager().getBeans(String.class, new 
AnnotationLiteral<QDepOverload>()
+        {
+        });
+        Assert.assertEquals("overloaded producer (same name, different 
parameters) must remain enabled", 1, depOverload.size());
+        Assert.assertEquals(BaseOverload.class, 
depOverload.iterator().next().getBeanClass());
+    }
+
+    public static class BaseOverload
+    {
+        @Produces
+        @QNoArg
+        public String m()
+        {
+            return "base-m";
+        }
+
+        @Produces
+        @QDepOverload
+        public String m(ProducerDep ignored)
+        {
+            return "base-m-dep";
+        }
+    }
+
+    /** Parameter type for the overloaded producer. */
+    public static class ProducerDep
+    {
+    }
+
+    public static class SubSpecializesNoArgOnly extends BaseOverload
+    {
+        @Produces
+        @Specializes
+        @QNoArg
+        public String m()
+        {
+            return "sub-m";
+        }
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, 
ElementType.TYPE})
+    @Qualifier
+    public @interface QNoArg
+    {
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, 
ElementType.TYPE})
+    @Qualifier
+    public @interface QDepOverload
+    {
+    }
+}

Reply via email to