From 3ef4e5d9a9e5d57f85964e2cebd20e5faa9860fe Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Thu, 7 Oct 2021 11:55:08 +0200 Subject: [PATCH] ArC build time optimization fix - BeanDeployment#beansByType - a bean should not be listed multiple times even if it has multiple types with the same raw name in its set of bean types - fix a regression introduced in #20470 - resolves #20566 --- .../quarkus/arc/processor/BeanDeployment.java | 16 +++--- .../beans/BeanRegistrarTest.java | 53 ++++++++++++++++--- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java index 1deca533a82e6..4f9ccde761def 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java @@ -291,28 +291,28 @@ void init(Consumer bytecodeTransformerConsumer, private void initBeanByTypeMap() { Map> map = new HashMap<>(); for (BeanInfo bean : beans) { - for (Type beanType : bean.types) { - if (DotNames.OBJECT.equals(beanType.name())) { + bean.types.stream().map(Type::name).distinct().forEach(rawTypeName -> { + if (DotNames.OBJECT.equals(rawTypeName)) { // Every bean has java.lang.Object - no need to cache results here - continue; + return; } - List beans = map.get(beanType.name()); + List beans = map.get(rawTypeName); if (beans == null) { // Very often, there will be exactly one bean for a given type - map.put(beanType.name(), List.of(bean)); + map.put(rawTypeName, List.of(bean)); } else { if (beans.size() == 1) { - map.put(beanType.name(), List.of(beans.get(0), bean)); + map.put(rawTypeName, List.of(beans.get(0), bean)); } else { BeanInfo[] array = new BeanInfo[beans.size() + 1]; for (int i = 0; i < beans.size(); i++) { array[i] = beans.get(i); } array[beans.size()] = bean; - map.put(beanType.name(), List.of(array)); + map.put(rawTypeName, List.of(array)); } } - } + }); } this.beansByType = map; } diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/buildextension/beans/BeanRegistrarTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/buildextension/beans/BeanRegistrarTest.java index dec25178504ed..06a86fe616e9e 100644 --- a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/buildextension/beans/BeanRegistrarTest.java +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/buildextension/beans/BeanRegistrarTest.java @@ -20,15 +20,19 @@ import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.Target; +import java.util.List; import java.util.Map; import java.util.Optional; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.util.AnnotationLiteral; +import javax.inject.Inject; import javax.inject.Qualifier; import javax.inject.Singleton; import org.jboss.jandex.DotName; +import org.jboss.jandex.ParameterizedType; import org.jboss.jandex.Type; +import org.jboss.jandex.Type.Kind; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -40,8 +44,9 @@ public class BeanRegistrarTest { @RegisterExtension public ArcTestContainer container = ArcTestContainer.builder() - .beanClasses(UselessBean.class, MyQualifier.class, NextQualifier.class) + .beanClasses(UselessBean.class, MyQualifier.class, NextQualifier.class, ListConsumer.class) .removeUnusedBeans(true) + .addRemovalExclusion(b -> b.hasType(DotName.createSimple(ListConsumer.class.getName()))) .beanRegistrars(new TestRegistrar()).build(); @AfterAll @@ -74,6 +79,18 @@ public void testSyntheticBean() { assertEquals(Integer.valueOf(152), Arc.container().instance(Integer.class).get()); assertEquals("Hello Frantisek!", Arc.container().instance(String.class).get()); assertEquals("Hello Roman!", Arc.container().instance(String.class, new NextQualifierLiteral()).get()); + @SuppressWarnings({ "resource" }) + List list = Arc.container().instance(ListConsumer.class).get().list; + assertEquals(1, list.size()); + assertEquals("foo", list.get(0)); + } + + @Singleton + static class ListConsumer { + + @Inject + List list; + } static class TestRegistrar implements BeanRegistrar { @@ -102,13 +119,28 @@ public void register(RegistrationContext context) { integerConfigurator.scope(Singleton.class); integerConfigurator.done(); - context.configure(String.class).unremovable().types(String.class).param("name", "Frantisek") - .creator(StringCreator.class).done(); + context.configure(String.class) + .unremovable() + .types(String.class) + .param("name", "Frantisek") + .creator(StringCreator.class) + .done(); context.configure(String.class).types(String.class).param("name", "Roman") - .creator(StringCreator.class).addQualifier().annotation(NextQualifier.class).addValue("name", "Roman") - .addValue("age", 42) - .addValue("classes", new Class[] { String.class }).done().unremovable().done(); + .creator(StringCreator.class) + .addQualifier().annotation(NextQualifier.class).addValue("name", "Roman").addValue("age", 42) + .addValue("classes", new Class[] { String.class }).done() + .unremovable() + .done(); + + context.configure(List.class) + // List, List + .addType(Type.create(DotName.createSimple(List.class.getName()), Kind.CLASS)) + .addType(ParameterizedType.create(DotName.createSimple(List.class.getName()), + new Type[] { Type.create(DotName.createSimple(String.class.getName()), Kind.CLASS) }, null)) + .creator(ListCreator.class) + .unremovable() + .done(); uselessBean = context.beans() .assignableTo( @@ -129,6 +161,15 @@ public String create(CreationalContext creationalContext, Map> { + + @Override + public List create(CreationalContext> creationalContext, Map params) { + return List.of("foo"); + } + + } + public static class SimpleDestroyer implements BeanDestroyer { @Override