From e0d0b1ae57c1e5c4438d553bc12c9293b256e440 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Wed, 4 Dec 2024 11:49:36 +0100 Subject: [PATCH] Arc - Introduce SyntheticBeanBuildItem#create. Arc - Allow adding whole type closures to BeanConfiguratorBase. Arc - Allow restricting bean types in BeanConfiguratorBase. --- .../deployment/SyntheticBeanBuildItem.java | 32 +++++ .../SyntheticBeanBuildItemCreateTest.java | 77 +++++++++++ ...SyntheticBeanBuildItemRemoveTypesTest.java | 103 ++++++++++++++ ...anBuildItemAddTypeClosureGenericsTest.java | 129 ++++++++++++++++++ ...theticBeanBuildItemAddTypeClosureTest.java | 100 ++++++++++++++ .../arc/processor/BeanConfigurator.java | 8 ++ .../arc/processor/BeanConfiguratorBase.java | 76 +++++++++++ .../quarkus/arc/processor/BeanRegistrar.java | 2 +- .../java/io/quarkus/arc/processor/Types.java | 32 +++++ 9 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/create/SyntheticBeanBuildItemCreateTest.java create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/removeTypes/SyntheticBeanBuildItemRemoveTypesTest.java create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureGenericsTest.java create mode 100644 extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureTest.java diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeanBuildItem.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeanBuildItem.java index 0bee6f858918c..91b10940263cf 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeanBuildItem.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/SyntheticBeanBuildItem.java @@ -32,6 +32,9 @@ public final class SyntheticBeanBuildItem extends MultiBuildItem { /** + * Returns a configurator object allowing for further customization of the synthetic bean. + *

+ * The implementation class is automatically registered as a resulting bean type. * * @param implClazz * @return a new configurator instance @@ -42,6 +45,9 @@ public static ExtendedBeanConfigurator configure(Class implClazz) { } /** + * Returns a configurator object allowing for further customization of the synthetic bean. + *

+ * The implementation class is automatically registered as a resulting bean type. * * @param implClazz * @return a new configurator instance @@ -51,6 +57,32 @@ public static ExtendedBeanConfigurator configure(DotName implClazz) { return new ExtendedBeanConfigurator(implClazz).addType(implClazz); } + /** + * Returns a configurator object allowing for further customization of the synthetic bean. + *

+ * Unlike {@link #configure(Class)}, the implementation class is not registered as a resulting bean type. + * + * @param implClazz + * @return a new configurator instance + * @see ExtendedBeanConfigurator#done() + */ + public static ExtendedBeanConfigurator create(Class implClazz) { + return create(DotName.createSimple(implClazz.getName())); + } + + /** + * Returns a configurator object allowing for further customization of the synthetic bean. + *

+ * Unlike {@link #configure(DotName)}, the implementation class is not registered as a resulting bean type. + * + * @param implClazz + * @return a new configurator instance + * @see ExtendedBeanConfigurator#done() + */ + public static ExtendedBeanConfigurator create(DotName implClazz) { + return new ExtendedBeanConfigurator(implClazz); + } + private final ExtendedBeanConfigurator configurator; SyntheticBeanBuildItem(ExtendedBeanConfigurator configurator) { diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/create/SyntheticBeanBuildItemCreateTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/create/SyntheticBeanBuildItemCreateTest.java new file mode 100644 index 0000000000000..9dbcf9e929612 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/create/SyntheticBeanBuildItemCreateTest.java @@ -0,0 +1,77 @@ +package io.quarkus.arc.test.synthetic.create; + +import java.util.function.Consumer; + +import jakarta.enterprise.inject.Vetoed; + +import org.jboss.jandex.DotName; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.BeanCreator; +import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.BuiltinScope; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.test.QuarkusUnitTest; + +/** + * Tests that {@link SyntheticBeanBuildItem#create(DotName)} does not add automatically register the param type as bean type + */ +public class SyntheticBeanBuildItemCreateTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(SyntheticBeanBuildItemCreateTest.class, FooCreator.class, FooInterface.class, Foo.class)) + .addBuildChainCustomizer(buildCustomizer()); + + static Consumer buildCustomizer() { + return new Consumer() { + + @Override + public void accept(BuildChainBuilder builder) { + builder.addBuildStep(new BuildStep() { + + @Override + public void execute(BuildContext context) { + context.produce(SyntheticBeanBuildItem.create(Foo.class) + .addType(FooInterface.class) + .scope(BuiltinScope.SINGLETON.getInfo()) + .unremovable() + .creator(FooCreator.class) + .done()); + } + }).produces(SyntheticBeanBuildItem.class).build(); + } + }; + } + + @Test + public void testBeanTypes() { + ArcContainer container = Arc.container(); + Assertions.assertFalse(container.select(Foo.class).isResolvable()); + Assertions.assertTrue(container.select(FooInterface.class).isResolvable()); + } + + @Vetoed + public static class Foo implements FooInterface { + } + + interface FooInterface { + } + + public static class FooCreator implements BeanCreator { + + @Override + public Foo create(SyntheticCreationalContext context) { + return new Foo(); + } + + } +} diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/removeTypes/SyntheticBeanBuildItemRemoveTypesTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/removeTypes/SyntheticBeanBuildItemRemoveTypesTest.java new file mode 100644 index 0000000000000..cbe724fbfc236 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/removeTypes/SyntheticBeanBuildItemRemoveTypesTest.java @@ -0,0 +1,103 @@ +package io.quarkus.arc.test.synthetic.removeTypes; + +import java.util.function.Consumer; + +import org.jboss.jandex.DotName; +import org.jboss.jandex.Type; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.BeanCreator; +import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.BuiltinScope; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.test.QuarkusUnitTest; + +public class SyntheticBeanBuildItemRemoveTypesTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(SyntheticBeanBuildItemRemoveTypesTest.class, FooCreator.class, FooInterface.class, Foo.class, + FooSubclass.class, Charlie.class, CharlieSubclass.class, CharlieInterface.class, BarInterface.class, + BazInterface.class)) + .addBuildChainCustomizer(buildCustomizer()); + + static Consumer buildCustomizer() { + return new Consumer() { + + @Override + public void accept(BuildChainBuilder builder) { + builder.addBuildStep(new BuildStep() { + + @Override + public void execute(BuildContext context) { + context.produce(SyntheticBeanBuildItem.create(FooSubclass.class) + .addTypeClosure(FooSubclass.class) + .removeTypes(DotName.createSimple(CharlieSubclass.class)) + .removeTypes(DotName.createSimple(FooSubclass.class)) + .removeTypes(Type.create(BazInterface.class)) + .scope(BuiltinScope.SINGLETON.getInfo()) + .unremovable() + .creator(FooCreator.class) + .done()); + } + }).produces(SyntheticBeanBuildItem.class).build(); + } + }; + } + + @Test + public void testRemovingBeanTypes() { + ArcContainer container = Arc.container(); + Assertions.assertTrue(container.select(Foo.class).isResolvable()); + Assertions.assertTrue(container.select(FooInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BarInterface.class).isResolvable()); + Assertions.assertTrue(container.select(Charlie.class).isResolvable()); + Assertions.assertTrue(container.select(CharlieInterface.class).isResolvable()); + + // CharlieSubclass, FooSubclass and BazInterface should not be registered as bean types + Assertions.assertFalse(container.select(CharlieSubclass.class).isResolvable()); + Assertions.assertFalse(container.select(FooSubclass.class).isResolvable()); + Assertions.assertFalse(container.select(BazInterface.class).isResolvable()); + } + + public static class FooSubclass extends Foo implements FooInterface { + } + + public static class Foo extends Charlie implements BazInterface { + } + + public static class CharlieSubclass extends Charlie { + } + + public static class Charlie implements CharlieInterface { + } + + interface CharlieInterface { + } + + interface FooInterface extends BarInterface { + } + + interface BarInterface { + } + + interface BazInterface { + } + + public static class FooCreator implements BeanCreator { + + @Override + public FooSubclass create(SyntheticCreationalContext context) { + return new FooSubclass(); + } + + } +} diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureGenericsTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureGenericsTest.java new file mode 100644 index 0000000000000..779aeff0de853 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureGenericsTest.java @@ -0,0 +1,129 @@ +package io.quarkus.arc.test.synthetic.typeClosure; + +import java.util.function.Consumer; + +import jakarta.enterprise.util.TypeLiteral; + +import org.jboss.jandex.ParameterizedType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.BeanCreator; +import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.BuiltinScope; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.test.QuarkusUnitTest; + +public class SyntheticBeanBuildItemAddTypeClosureGenericsTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(SyntheticBeanBuildItemAddTypeClosureGenericsTest.class, FooCreator.class, FooInterface.class, + Foo.class, + FooSubclass.class, Charlie.class, CharlieSubclass.class, CharlieInterface.class, BarInterface.class, + BazInterface.class, Alpha.class, Beta.class)) + .addBuildChainCustomizer(buildCustomizer()); + + static Consumer buildCustomizer() { + return new Consumer() { + + @Override + public void accept(BuildChainBuilder builder) { + builder.addBuildStep(new BuildStep() { + + @Override + public void execute(BuildContext context) { + context.produce(SyntheticBeanBuildItem.create(FooSubclass.class) + .addTypeClosure(ParameterizedType.builder(FooSubclass.class).addArgument(Beta.class).build()) + .scope(BuiltinScope.SINGLETON.getInfo()) + .unremovable() + .creator(FooCreator.class) + .done()); + } + }).produces(SyntheticBeanBuildItem.class).build(); + } + }; + } + + @Test + public void testBeanTypesDiscovered() { + ArcContainer container = Arc.container(); + + // Foo/Bar/Baz interfaces should work normally, no generics there + Assertions.assertTrue(container.select(FooInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BarInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BazInterface.class).isResolvable()); + + // FooSubclass is resolvable only as correct parameterized type + Assertions.assertTrue(container.select(new TypeLiteral>() { + }).isResolvable()); + Assertions.assertFalse(container.select(new TypeLiteral>() { + }).isResolvable()); + Assertions.assertFalse(container.select(FooSubclass.class).isResolvable()); + + // Foo type should work only parameterized + Assertions.assertTrue(container.select(new TypeLiteral>() { + }).isResolvable()); + Assertions.assertFalse(container.select(Foo.class).isResolvable()); + + // Foo extends Charlie raw type + // we should be able to perform resolution for raw type but not for a parameterized type + Assertions.assertTrue(container.select(Charlie.class).isResolvable()); + Assertions.assertTrue(container.select(CharlieInterface.class).isResolvable()); + Assertions.assertFalse(container.select(new TypeLiteral>() { + }).isResolvable()); + Assertions.assertFalse(container.select(new TypeLiteral>() { + }).isResolvable()); + + // CharlieSubclass should not be discovered as bean type + Assertions.assertFalse(container.select(CharlieSubclass.class).isResolvable()); + } + + public static class Alpha { + + } + + public static class Beta { + + } + + public static class FooSubclass extends Foo implements FooInterface { + } + + public static class Foo extends Charlie implements BazInterface { + } + + public static class CharlieSubclass extends Charlie { + } + + public static class Charlie implements CharlieInterface { + } + + interface CharlieInterface { + } + + interface FooInterface extends BarInterface { + } + + interface BarInterface { + } + + interface BazInterface { + } + + public static class FooCreator implements BeanCreator> { + + @Override + public FooSubclass create(SyntheticCreationalContext> context) { + return new FooSubclass(); + } + + } +} diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureTest.java new file mode 100644 index 0000000000000..3801726f44eb7 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/synthetic/typeClosure/SyntheticBeanBuildItemAddTypeClosureTest.java @@ -0,0 +1,100 @@ +package io.quarkus.arc.test.synthetic.typeClosure; + +import java.util.function.Consumer; + +import org.jboss.jandex.DotName; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; +import io.quarkus.arc.BeanCreator; +import io.quarkus.arc.SyntheticCreationalContext; +import io.quarkus.arc.deployment.SyntheticBeanBuildItem; +import io.quarkus.arc.processor.BuiltinScope; +import io.quarkus.builder.BuildChainBuilder; +import io.quarkus.builder.BuildContext; +import io.quarkus.builder.BuildStep; +import io.quarkus.test.QuarkusUnitTest; + +public class SyntheticBeanBuildItemAddTypeClosureTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(SyntheticBeanBuildItemAddTypeClosureTest.class, FooCreator.class, FooInterface.class, Foo.class, + FooSubclass.class, Charlie.class, CharlieSubclass.class, CharlieInterface.class, BarInterface.class, + BazInterface.class)) + .addBuildChainCustomizer(buildCustomizer()); + + static Consumer buildCustomizer() { + return new Consumer() { + + @Override + public void accept(BuildChainBuilder builder) { + builder.addBuildStep(new BuildStep() { + + @Override + public void execute(BuildContext context) { + context.produce(SyntheticBeanBuildItem.create(FooSubclass.class) + .addTypeClosure(FooInterface.class) + .addTypeClosure(DotName.createSimple(Foo.class)) + .scope(BuiltinScope.SINGLETON.getInfo()) + .unremovable() + .creator(FooCreator.class) + .done()); + } + }).produces(SyntheticBeanBuildItem.class).build(); + } + }; + } + + @Test + public void testBeanTypesDiscovered() { + ArcContainer container = Arc.container(); + Assertions.assertTrue(container.select(Foo.class).isResolvable()); + Assertions.assertTrue(container.select(FooInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BarInterface.class).isResolvable()); + Assertions.assertTrue(container.select(Charlie.class).isResolvable()); + Assertions.assertTrue(container.select(CharlieInterface.class).isResolvable()); + Assertions.assertTrue(container.select(BazInterface.class).isResolvable()); + + // Charlie and Foo subclasses should not be registered as bean types + Assertions.assertFalse(container.select(CharlieSubclass.class).isResolvable()); + Assertions.assertFalse(container.select(FooSubclass.class).isResolvable()); + } + + public static class FooSubclass extends Foo implements FooInterface { + } + + public static class Foo extends Charlie implements BazInterface { + } + + public static class CharlieSubclass extends Charlie { + } + + public static class Charlie implements CharlieInterface { + } + + interface CharlieInterface { + } + + interface FooInterface extends BarInterface { + } + + interface BarInterface { + } + + interface BazInterface { + } + + public static class FooCreator implements BeanCreator { + + @Override + public FooSubclass create(SyntheticCreationalContext context) { + return new FooSubclass(); + } + + } +} diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfigurator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfigurator.java index 156df45341604..80f7b6add09fd 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfigurator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfigurator.java @@ -85,6 +85,14 @@ public void done() { .build()); } + // perform type discovery for registered types + for (Type jandexType : registeredTypeClosures) { + this.types.addAll(Types.getTypeClosureFromJandexType(jandexType, beanDeployment).unrestrictedTypes()); + } + + // restrict resulting bean types if needed + this.types.removeAll(typesToRemove); + BeanInfo.Builder builder = new BeanInfo.Builder() .implClazz(implClass) .identifier(identifier) diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfiguratorBase.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfiguratorBase.java index 84644292fd52a..f2992031c8ba4 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfiguratorBase.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanConfiguratorBase.java @@ -45,6 +45,8 @@ public abstract class BeanConfiguratorBase types; + protected final Set registeredTypeClosures; + protected final Set typesToRemove; protected final Set qualifiers; protected ScopeInfo scope; protected Boolean alternative; @@ -66,6 +68,8 @@ public abstract class BeanConfiguratorBase(); + this.registeredTypeClosures = new HashSet<>(); + this.typesToRemove = new HashSet<>(); this.qualifiers = new HashSet<>(); this.stereotypes = new ArrayList<>(); this.removable = true; @@ -83,6 +87,10 @@ public THIS read(BeanConfiguratorBase base) { identifier = base.identifier; types.clear(); types.addAll(base.types); + registeredTypeClosures.clear(); + registeredTypeClosures.addAll(base.registeredTypeClosures); + typesToRemove.clear(); + typesToRemove.addAll(base.typesToRemove); qualifiers.clear(); qualifiers.addAll(base.qualifiers); scope = base.scope; @@ -134,6 +142,74 @@ public THIS addType(Class type) { return addType(DotName.createSimple(type.getName())); } + /** + * Adds an unrestricted set of bean types for the given type as if it represented a bean class of a managed bean. + * + * @param typeName {@link DotName} representation of a class that should be scanned for types + * @return self + */ + public THIS addTypeClosure(DotName typeName) { + return addTypeClosure(Type.create(typeName, Kind.CLASS)); + } + + /** + * Adds an unrestricted set of bean types for the given type as if it represented a bean class of a managed bean. + * + * @param type a class that should be scanned for types + * @return self + */ + public THIS addTypeClosure(Class type) { + return addTypeClosure(Type.create(type)); + } + + /** + * Adds an unrestricted set of bean types for the given type as if it represented a bean class of a managed bean. + * + * @param type {@link Type} representation of a class that should be scanned for types + * @return self + */ + public THIS addTypeClosure(Type type) { + this.registeredTypeClosures.add(type); + return self(); + } + + /** + * Removes listed types from the resulting types of the synthetic bean. + * + * @param types types that should be removed from the resulting set of bean types + * @return self + */ + public THIS removeTypes(Class... types) { + for (Class classType : types) { + removeTypes(Type.create(classType)); + } + return self(); + } + + /** + * Removes listed types from the resulting types of the synthetic bean. + * + * @param types types that should be removed from the resulting set of bean types + * @return self + */ + public THIS removeTypes(DotName... types) { + for (DotName name : types) { + removeTypes(Type.create(name, Kind.CLASS)); + } + return self(); + } + + /** + * Removes listed types from the resulting types of the synthetic bean. + * + * @param types types that should be removed from the resulting set of bean types + * @return self + */ + public THIS removeTypes(Type... types) { + Collections.addAll(this.typesToRemove, types); + return self(); + } + public THIS addQualifier(Class annotationClass) { return addQualifier(DotName.createSimple(annotationClass.getName())); } diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanRegistrar.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanRegistrar.java index fb21183066102..c1307f808b520 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanRegistrar.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanRegistrar.java @@ -25,7 +25,7 @@ interface RegistrationContext extends BuildContext { * Configure a new synthetic bean. The bean is not added to the deployment unless the {@link BeanConfigurator#done()} * method is called. * - * @param beanClass + * @param beanClassName * @return a new synthetic bean configurator */ BeanConfigurator configure(DotName beanClassName); diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java index a2018013dc4c4..e085ef67e1516 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java @@ -522,6 +522,38 @@ record TypeClosure(Set types, Set unrestrictedTypes) { } } + static TypeClosure getTypeClosureFromJandexType(Type jandexType, BeanDeployment beanDeployment) { + Set types; + Set unrestrictedBeanTypes = new HashSet<>(); + if (jandexType.kind() == Kind.TYPE_VARIABLE) { + throw new IllegalStateException("A type variable is not a legal bean type"); + } + if (jandexType.kind() == Kind.PRIMITIVE || jandexType.kind() == Kind.ARRAY) { + types = new HashSet<>(); + types.add(jandexType); + types.add(OBJECT_TYPE); + return new TypeClosure(types); + } else { + ClassInfo jandexTypeClassInfo = getClassByName(beanDeployment.getBeanArchiveIndex(), jandexType); + if (jandexTypeClassInfo == null) { + throw new IllegalArgumentException( + "Provided Jandex type not found in index: " + jandexType.name()); + } + if (Kind.CLASS.equals(jandexType.kind())) { + types = getTypeClosure(jandexTypeClassInfo, null, Collections.emptyMap(), beanDeployment, null, + unrestrictedBeanTypes); + } else if (Kind.PARAMETERIZED_TYPE.equals(jandexType.kind())) { + types = getTypeClosure(jandexTypeClassInfo, null, + buildResolvedMap(jandexType.asParameterizedType().arguments(), jandexTypeClassInfo.typeParameters(), + Collections.emptyMap(), beanDeployment.getBeanArchiveIndex()), + beanDeployment, null, unrestrictedBeanTypes); + } else { + throw new IllegalArgumentException("Unsupported return type"); + } + } + return new TypeClosure(types, unrestrictedBeanTypes); + } + static Set getClassUnrestrictedTypeClosure(ClassInfo classInfo, BeanDeployment beanDeployment) { Set types; Set unrestrictedBeanTypes = new HashSet<>();