Repository: quarkusio/quarkus
Issue: Removal of beans loads referenced classes

### Describe the bug

I have following project structure:
* commons (external module)
* web (quarkus)

The commons module includes hibernate-validator (and custom ConstraintValidators), which I just don't need for this project.
I tried to simply add an exclusion on quarkus-hibernate-validator, to remove this extension.

However, I got the exception from below.
Apperantly, during removal of unused beans, the bean is initialized?

```
@ApplicationScoped
public class FutureDayValidator implements ConstraintValidator<FutureDay, Date> {

    @Override
    public void initialize(FutureDay constraintAnnotation) {
    }

    @Override
    public boolean isValid(Date value, ConstraintValidatorContext context) {
return false;
    }
}
```

### Expected behavior

App starts, just with the ConstraintValidator removed. 

### Actual behavior

```
2022-03-16 08:22:17,682 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus: java.lang.RuntimeException: java.lang.NoClassDefFoundError: javax/validation/ConstraintValidator
        at io.quarkus.dev.appstate.ApplicationStateNotification.waitForApplicationStart(ApplicationStateNotification.java:51)
        at io.quarkus.runner.bootstrap.StartupActionImpl.runMainClass(StartupActionImpl.java:122)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.firstStart(IsolatedDevModeMain.java:144)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:455)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:66)
        at io.quarkus.bootstrap.app.CuratedApplication.runInCl(CuratedApplication.java:140)
        at io.quarkus.bootstrap.app.CuratedApplication.runInAugmentClassLoader(CuratedApplication.java:96)
        at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:132)
        at io.quarkus.deployment.dev.DevModeMain.main(DevModeMain.java:62)
Caused by: java.lang.NoClassDefFoundError: javax/validation/ConstraintValidator
        at java.base/java.lang.ClassLoader.defineClass1(Native Method)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:454)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:414)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:467)
        at io.quarkus.arc.setup.Default_ComponentsProvider.addRemovedBeans2(Unknown Source)
        at io.quarkus.arc.setup.Default_ComponentsProvider.getComponents(Unknown Source)
        at io.quarkus.arc.impl.ArcContainerImpl.<init>(ArcContainerImpl.java:118)
        at io.quarkus.arc.Arc.initialize(Arc.java:24)
        at io.quarkus.arc.runtime.ArcRecorder.getContainer(ArcRecorder.java:40)
        at io.quarkus.deployment.steps.ArcProcessor$generateResources686947423.deploy_0(Unknown Source)
        at io.quarkus.deployment.steps.ArcProcessor$generateResources686947423.deploy(Unknown Source)
        at io.quarkus.runner.ApplicationImpl.<clinit>(Unknown Source)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
        at java.base/java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:128)
        at java.base/jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:347)
        at java.base/java.lang.Class.newInstance(Class.java:645)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:66)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:41)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:120)
        at io.quarkus.runner.GeneratedMain.main(Unknown Source)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at io.quarkus.runner.bootstrap.StartupActionImpl$1.run(StartupActionImpl.java:103)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ClassNotFoundException: javax.validation.ConstraintValidator
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:464)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:414)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:464)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:414)
        ... 31 more

```

### How to Reproduce?

Download the reproducer: 
[removed-bean-classloading.zip](https://github.com/quarkusio/quarkus/files/8260177/removed-bean-classloading.zip)


1. mvn quarkus:dev
2. Exception happens
3. Remove exclusion on hibernate-validator in web/pom.xml
4. mvn quarkus:dev
5. It starts

### Output of `uname -a` or `ver`

Microsoft Windows [Version 10.0.19044.1586]

### Output of `java -version`

openjdk 17.0.2 2022-01-18 OpenJDK Runtime Environment Temurin-17.0.2+8 (build 17.0.2+8) OpenJDK 64-Bit Server VM Temurin-17.0.2+8 (build 17.0.2+8, mixed mode, sharing)

### GraalVM version (if different from Java)

_No response_

### Quarkus version or git rev

2.7.4.Final

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537) Maven home: C:\\eclipse\\tools\\java\\maven Java version: 17.0.2, vendor: Eclipse Adoptium, runtime: C:\\eclipse\\tools\\java\\17 Default locale: de_DE, platform encoding: Cp1252 OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

### Additional information

_No response_

Changed files:
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Types.java
independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ComponentsProvider.java
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ComponentsProviderGenerator.java

diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ComponentsProviderGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ComponentsProviderGenerator.java
index 9a2effe1669..475b0c7044a 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ComponentsProviderGenerator.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ComponentsProviderGenerator.java
@@ -9,12 +9,16 @@
 import io.quarkus.arc.ComponentsProvider;
 import io.quarkus.arc.InjectableBean;
 import io.quarkus.arc.processor.ResourceOutput.Resource;
+import io.quarkus.gizmo.AssignableResultHandle;
+import io.quarkus.gizmo.BytecodeCreator;
+import io.quarkus.gizmo.CatchBlockCreator;
 import io.quarkus.gizmo.ClassCreator;
 import io.quarkus.gizmo.ClassOutput;
 import io.quarkus.gizmo.FieldDescriptor;
 import io.quarkus.gizmo.MethodCreator;
 import io.quarkus.gizmo.MethodDescriptor;
 import io.quarkus.gizmo.ResultHandle;
+import io.quarkus.gizmo.TryBlock;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -120,8 +124,10 @@ Collection<Resource> generate(String name, BeanDeployment beanDeployment, Map<Be
 
         // Break removed beans processing into multiple addRemovedBeans() methods
         ResultHandle removedBeansHandle = getComponents.newInstance(MethodDescriptor.ofConstructor(ArrayList.class));
+        ResultHandle typeCacheHandle = getComponents.newInstance(MethodDescriptor.ofConstructor(HashMap.class));
         if (detectUnusedFalsePositives) {
-            processRemovedBeans(componentsProvider, getComponents, removedBeansHandle, beanDeployment, classOutput);
+            processRemovedBeans(componentsProvider, getComponents, removedBeansHandle, typeCacheHandle, beanDeployment,
+                    classOutput);
         }
 
         // Qualifier non-binding members
@@ -232,9 +238,10 @@ private void processObservers(ClassCreator componentsProvider, MethodCreator get
     }
 
     private void processRemovedBeans(ClassCreator componentsProvider, MethodCreator getComponents,
-            ResultHandle removedBeansHandle, BeanDeployment beanDeployment, ClassOutput classOutput) {
+            ResultHandle removedBeansHandle, ResultHandle typeCacheHandle, BeanDeployment beanDeployment,
+            ClassOutput classOutput) {
         try (RemovedBeanAdder removedBeanAdder = new RemovedBeanAdder(componentsProvider, getComponents, removedBeansHandle,
-                classOutput)) {
+                typeCacheHandle, classOutput)) {
             for (BeanInfo remnovedBean : beanDeployment.getRemovedBeans()) {
                 removedBeanAdder.addComponent(remnovedBean);
             }
@@ -385,34 +392,40 @@ void addComponentInternal(ObserverInfo observer) {
     class RemovedBeanAdder extends ComponentAdder<BeanInfo> {
 
         private final ResultHandle removedBeansHandle;
+        private final ResultHandle typeCacheHandle;
         private final ClassOutput classOutput;
         private ResultHandle tccl;
         // Shared annotation literals for an individual addRemovedBeansX() method
         private final Map<AnnotationInstanceKey, ResultHandle> sharedQualifers;
-        // Shared java.lang.reflect.Type instances for an individual addRemovedBeansX() method
-        private final Map<org.jboss.jandex.Type, ResultHandle> sharedTypes;
+
+        private final MapTypeCache typeCache;
 
         public RemovedBeanAdder(ClassCreator componentsProvider, MethodCreator getComponentsMethod,
-                ResultHandle removedBeansHandle, ClassOutput classOutput) {
+                ResultHandle removedBeansHandle, ResultHandle typeCacheHandle, ClassOutput classOutput) {
             super(getComponentsMethod, componentsProvider);
             this.removedBeansHandle = removedBeansHandle;
+            this.typeCacheHandle = typeCacheHandle;
             this.classOutput = classOutput;
             this.sharedQualifers = new HashMap<>();
-            this.sharedTypes = new HashMap<>();
+            this.typeCache = new MapTypeCache();
         }
 
         @Override
         MethodCreator newAddMethod() {
             // Clear the shared maps for each addRemovedBeansX() method
             sharedQualifers.clear();
-            sharedTypes.clear();
 
-            MethodCreator addMethod = componentsProvider.getMethodCreator(ADD_REMOVED_BEANS + group++, void.class, List.class)
+            // private void addRemovedBeans1(List removedBeans, List typeCache)
+            MethodCreator addMethod = componentsProvider
+                    .getMethodCreator(ADD_REMOVED_BEANS + group++, void.class, List.class, Map.class)
                     .setModifiers(ACC_PRIVATE);
             // Get the TCCL - we will use it later
             ResultHandle currentThread = addMethod
                     .invokeStaticMethod(MethodDescriptors.THREAD_CURRENT_THREAD);
             tccl = addMethod.invokeVirtualMethod(MethodDescriptors.THREAD_GET_TCCL, currentThread);
+
+            typeCache.initialize(addMethod);
+
             return addMethod;
         }
 
@@ -420,8 +433,8 @@ MethodCreator newAddMethod() {
         void invokeAddMethod() {
             getComponentsMethod.invokeVirtualMethod(
                     MethodDescriptor.ofMethod(componentsProvider.getClassName(),
-                            addMethod.getMethodDescriptor().getName(), void.class, List.class),
-                    getComponentsMethod.getThis(), removedBeansHandle);
+                            addMethod.getMethodDescriptor().getName(), void.class, List.class, Map.class),
+                    getComponentsMethod.getThis(), removedBeansHandle, typeCacheHandle);
         }
 
         @Override
@@ -436,14 +449,20 @@ void addComponentInternal(BeanInfo removedBean) {
                     // Skip java.lang.Object
                     continue;
                 }
-                ResultHandle typeHandle;
+
+                TryBlock tryBlock = addMethod.tryBlock();
+                CatchBlockCreator catchBlock = tryBlock.addCatch(Throwable.class);
+                catchBlock.invokeStaticInterfaceMethod(
+                        MethodDescriptors.COMPONENTS_PROVIDER_UNABLE_TO_LOAD_REMOVED_BEAN_TYPE,
+                        catchBlock.load(type.toString()), catchBlock.getCaughtException());
+                AssignableResultHandle typeHandle = tryBlock.createVariable(Object.class);
                 try {
-                    typeHandle = Types.getTypeHandle(addMethod, type, tccl, sharedTypes);
+                    Types.getTypeHandle(typeHandle, tryBlock, type, tccl, typeCache);
                 } catch (IllegalArgumentException e) {
                     throw new IllegalStateException(
                             "Unable to construct the type handle for " + removedBean + ": " + e.getMessage());
                 }
-                addMethod.invokeInterfaceMethod(MethodDescriptors.SET_ADD, typesHandle, typeHandle);
+                tryBlock.invokeInterfaceMethod(MethodDescriptors.SET_ADD, typesHandle, typeHandle);
             }
 
             // Qualifiers
@@ -513,6 +532,27 @@ void addComponentInternal(BeanInfo removedBean) {
 
     }
 
+    static class MapTypeCache implements Types.TypeCache {
+
+        private ResultHandle mapHandle;
+
+        @Override
+        public void initialize(MethodCreator method) {
+            this.mapHandle = method.getMethodParam(1);
+        }
+
+        @Override
+        public ResultHandle get(org.jboss.jandex.Type type, BytecodeCreator bytecode) {
+            return bytecode.invokeInterfaceMethod(MethodDescriptors.MAP_GET, mapHandle, bytecode.load(type.toString()));
+        }
+
+        @Override
+        public void put(org.jboss.jandex.Type type, ResultHandle value, BytecodeCreator bytecode) {
+            bytecode.invokeInterfaceMethod(MethodDescriptors.MAP_PUT, mapHandle, bytecode.load(type.toString()), value);
+        }
+
+    }
+
     static class BeanAdder extends ComponentAdder<BeanInfo> {
 
         private final Set<BeanInfo> processedBeans;
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java
index 06622c2f085..b1f8dfad9ed 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/MethodDescriptors.java
@@ -3,6 +3,7 @@
 import io.quarkus.arc.Arc;
 import io.quarkus.arc.ArcContainer;
 import io.quarkus.arc.ClientProxy;
+import io.quarkus.arc.ComponentsProvider;
 import io.quarkus.arc.InjectableBean;
 import io.quarkus.arc.InjectableBean.Kind;
 import io.quarkus.arc.InjectableContext;
@@ -80,6 +81,8 @@ public final class MethodDescriptors {
 
     public static final MethodDescriptor LIST_ADD = MethodDescriptor.ofMethod(List.class, "add", boolean.class, Object.class);
 
+    public static final MethodDescriptor LIST_GET = MethodDescriptor.ofMethod(List.class, "get", Object.class, int.class);
+
     public static final MethodDescriptor OBJECT_EQUALS = MethodDescriptor.ofMethod(Object.class, "equals", boolean.class,
             Object.class);
 
@@ -265,6 +268,10 @@ public final class MethodDescriptors {
             .ofMethod(Instances.class, "listOfHandles", List.class, InjectableBean.class, Type.class, Type.class,
                     Set.class, CreationalContextImpl.class, Set.class, Member.class, int.class);
 
+    public static final MethodDescriptor COMPONENTS_PROVIDER_UNABLE_TO_LOAD_REMOVED_BEAN_TYPE = MethodDescriptor.ofMethod(
+            ComponentsProvider.class, "unableToLoadRemovedBeanType",
+            void.class, String.class, Throwable.class);
+
     private MethodDescriptors() {
     }
 
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 28284991d4e..50913ddd9bd 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
@@ -6,7 +6,10 @@
 import io.quarkus.arc.impl.ParameterizedTypeImpl;
 import io.quarkus.arc.impl.TypeVariableImpl;
 import io.quarkus.arc.impl.WildcardTypeImpl;
+import io.quarkus.gizmo.AssignableResultHandle;
+import io.quarkus.gizmo.BranchResult;
 import io.quarkus.gizmo.BytecodeCreator;
+import io.quarkus.gizmo.MethodCreator;
 import io.quarkus.gizmo.MethodDescriptor;
 import io.quarkus.gizmo.ResultHandle;
 import java.util.ArrayList;
@@ -76,24 +79,26 @@ public static ResultHandle getTypeHandle(BytecodeCreator creator, Type type) {
     }
 
     public static ResultHandle getTypeHandle(BytecodeCreator creator, Type type, ResultHandle tccl) {
-        return getTypeHandle(creator, type, tccl, null);
+        AssignableResultHandle result = creator.createVariable(Object.class);
+        getTypeHandle(result, creator, type, tccl, null);
+        return result;
     }
 
-    static ResultHandle getTypeHandle(BytecodeCreator creator, Type type, ResultHandle tccl,
-            Map<Type, ResultHandle> sharedTypes) {
-        if (sharedTypes != null) {
-            ResultHandle sharedType = sharedTypes.get(type);
-            if (sharedType != null) {
-                return sharedType;
-            }
+    static void getTypeHandle(AssignableResultHandle variable, BytecodeCreator creator, Type type, ResultHandle tccl,
+            TypeCache cache) {
+        if (cache != null) {
+            ResultHandle cachedType = cache.get(type, creator);
+            BranchResult cachedNull = creator.ifNull(cachedType);
+            cachedNull.falseBranch().assign(variable, cachedType);
+            creator = cachedNull.trueBranch();
         }
         if (Kind.CLASS.equals(type.kind())) {
             String className = type.asClassType().name().toString();
             ResultHandle classHandle = doLoadClass(creator, className, tccl);
-            if (sharedTypes != null) {
-                sharedTypes.put(type, classHandle);
+            if (cache != null) {
+                cache.put(type, classHandle, creator);
             }
-            return classHandle;
+            creator.assign(variable, classHandle);
         } else if (Kind.TYPE_VARIABLE.equals(type.kind())) {
             // E.g. T -> new TypeVariableImpl("T")
             TypeVariable typeVariable = type.asTypeVariable();
@@ -104,69 +109,85 @@ static ResultHandle getTypeHandle(BytecodeCreator creator, Type type, ResultHand
             } else {
                 boundsHandle = creator.newArray(java.lang.reflect.Type.class, creator.load(bounds.size()));
                 for (int i = 0; i < bounds.size(); i++) {
-                    creator.writeArrayValue(boundsHandle, i, getTypeHandle(creator, bounds.get(i), tccl, sharedTypes));
+                    AssignableResultHandle boundHandle = creator.createVariable(Object.class);
+                    getTypeHandle(boundHandle, creator, bounds.get(i), tccl, cache);
+                    creator.writeArrayValue(boundsHandle, i, boundHandle);
                 }
             }
             ResultHandle typeVariableHandle = creator.newInstance(
                     MethodDescriptor.ofConstructor(TypeVariableImpl.class, String.class, java.lang.reflect.Type[].class),
                     creator.load(typeVariable.identifier()), boundsHandle);
-            if (sharedTypes != null) {
-                sharedTypes.put(typeVariable, typeVariableHandle);
+            if (cache != null) {
+                cache.put(typeVariable, typeVariableHandle, creator);
             }
-            return typeVariableHandle;
+            creator.assign(variable, typeVariableHandle);
 
         } else if (Kind.PARAMETERIZED_TYPE.equals(type.kind())) {
             // E.g. List<String> -> new ParameterizedTypeImpl(List.class, String.class)
-            return getParameterizedType(creator, tccl, type.asParameterizedType(), sharedTypes);
+            getParameterizedType(variable, creator, tccl, type.asParameterizedType(), cache);
 
         } else if (Kind.ARRAY.equals(type.kind())) {
             Type componentType = type.asArrayType().component();
             // E.g. String[] -> new GenericArrayTypeImpl(String.class)
+            AssignableResultHandle componentTypeHandle = creator.createVariable(Object.class);
+            getTypeHandle(componentTypeHandle, creator, componentType, tccl, cache);
             ResultHandle arrayHandle = creator.newInstance(
                     MethodDescriptor.ofConstructor(GenericArrayTypeImpl.class, java.lang.reflect.Type.class),
-                    getTypeHandle(creator, componentType, tccl, sharedTypes));
-            if (sharedTypes != null) {
-                sharedTypes.put(type, arrayHandle);
+                    componentTypeHandle);
+            if (cache != null) {
+                cache.put(type, arrayHandle, creator);
             }
-            return arrayHandle;
+            creator.assign(variable, arrayHandle);
 
         } else if (Kind.WILDCARD_TYPE.equals(type.kind())) {
             // E.g. ? extends Number -> WildcardTypeImpl.withUpperBound(Number.class)
             WildcardType wildcardType = type.asWildcardType();
             ResultHandle wildcardHandle;
             if (wildcardType.superBound() == null) {
+                AssignableResultHandle extendsBoundHandle = creator.createVariable(Object.class);
+                getTypeHandle(extendsBoundHandle, creator, wildcardType.extendsBound(), tccl, cache);
                 wildcardHandle = creator.invokeStaticMethod(
                         MethodDescriptor.ofMethod(WildcardTypeImpl.class, "withUpperBound",
                                 java.lang.reflect.WildcardType.class, java.lang.reflect.Type.class),
-                        getTypeHandle(creator, wildcardType.extendsBound(), tccl, sharedTypes));
+                        extendsBoundHandle);
             } else {
+                AssignableResultHandle superBoundHandle = creator.createVariable(Object.class);
+                getTypeHandle(superBoundHandle, creator, wildcardType.superBound(), tccl, cache);
                 wildcardHandle = creator.invokeStaticMethod(
                         MethodDescriptor.ofMethod(WildcardTypeImpl.class, "withLowerBound",
                                 java.lang.reflect.WildcardType.class, java.lang.reflect.Type.class),
-                        getTypeHandle(creator, wildcardType.superBound(), tccl, sharedTypes));
+                        superBoundHandle);
             }
-            if (sharedTypes != null) {
-                sharedTypes.put(wildcardType, wildcardHandle);
+            if (cache != null) {
+                cache.put(wildcardType, wildcardHandle, creator);
             }
-            return wildcardHandle;
+            creator.assign(variable, wildcardHandle);
         } else if (Kind.PRIMITIVE.equals(type.kind())) {
             switch (type.asPrimitiveType().primitive()) {
                 case INT:
-                    return creator.loadClassFromTCCL(int.class);
+                    creator.assign(variable, creator.loadClassFromTCCL(int.class));
+                    break;
                 case LONG:
-                    return creator.loadClassFromTCCL(long.class);
+                    creator.assign(variable, creator.loadClassFromTCCL(long.class));
+                    break;
                 case BOOLEAN:
-                    return creator.loadClassFromTCCL(boolean.class);
+                    creator.assign(variable, creator.loadClassFromTCCL(boolean.class));
+                    break;
                 case BYTE:
-                    return creator.loadClassFromTCCL(byte.class);
+                    creator.assign(variable, creator.loadClassFromTCCL(byte.class));
+                    break;
                 case CHAR:
-                    return creator.loadClassFromTCCL(char.class);
+                    creator.assign(variable, creator.loadClassFromTCCL(char.class));
+                    break;
                 case DOUBLE:
-                    return creator.loadClassFromTCCL(double.class);
+                    creator.assign(variable, creator.loadClassFromTCCL(double.class));
+                    break;
                 case FLOAT:
-                    return creator.loadClassFromTCCL(float.class);
+                    creator.assign(variable, creator.loadClassFromTCCL(float.class));
+                    break;
                 case SHORT:
-                    return creator.loadClassFromTCCL(short.class);
+                    creator.assign(variable, creator.loadClassFromTCCL(short.class));
+                    break;
                 default:
                     throw new IllegalArgumentException("Unsupported primitive type: " + type);
             }
@@ -175,37 +196,46 @@ static ResultHandle getTypeHandle(BytecodeCreator creator, Type type, ResultHand
         }
     }
 
-    static ResultHandle getParameterizedType(BytecodeCreator creator, ResultHandle tccl,
-            ParameterizedType parameterizedType, Map<Type, ResultHandle> sharedTypes) {
+    static void getParameterizedType(AssignableResultHandle variable, BytecodeCreator creator, ResultHandle tccl,
+            ParameterizedType parameterizedType, TypeCache cache) {
         List<Type> arguments = parameterizedType.arguments();
         ResultHandle typeArgsHandle = creator.newArray(java.lang.reflect.Type.class, creator.load(arguments.size()));
         for (int i = 0; i < arguments.size(); i++) {
-            creator.writeArrayValue(typeArgsHandle, i, getTypeHandle(creator, arguments.get(i), tccl, sharedTypes));
+            AssignableResultHandle argumentHandle = creator.createVariable(Object.class);
+            getTypeHandle(argumentHandle, creator, arguments.get(i), tccl, cache);
+            creator.writeArrayValue(typeArgsHandle, i, argumentHandle);
         }
         Type rawType = Type.create(parameterizedType.name(), Kind.CLASS);
         ResultHandle rawTypeHandle = null;
-        if (sharedTypes != null) {
-            rawTypeHandle = sharedTypes.get(rawType);
+        if (cache != null) {
+            rawTypeHandle = cache.get(rawType, creator);
         }
         if (rawTypeHandle == null) {
             rawTypeHandle = doLoadClass(creator, parameterizedType.name().toString(), tccl);
-            if (sharedTypes != null) {
-                sharedTypes.put(rawType, rawTypeHandle);
+            if (cache != null) {
+                cache.put(rawType, rawTypeHandle, creator);
             }
         }
         ResultHandle parameterizedTypeHandle = creator.newInstance(
                 MethodDescriptor.ofConstructor(ParameterizedTypeImpl.class, java.lang.reflect.Type.class,
                         java.lang.reflect.Type[].class),
                 rawTypeHandle, typeArgsHandle);
-        if (sharedTypes != null) {
-            sharedTypes.put(parameterizedType, parameterizedTypeHandle);
+        if (cache != null) {
+            cache.put(parameterizedType, parameterizedTypeHandle, creator);
         }
-        return parameterizedTypeHandle;
+        creator.assign(variable, parameterizedTypeHandle);
+    }
+
+    public static void getParameterizedType(AssignableResultHandle variable, BytecodeCreator creator, ResultHandle tccl,
+            ParameterizedType parameterizedType) {
+        getParameterizedType(variable, creator, tccl, parameterizedType, null);
     }
 
     public static ResultHandle getParameterizedType(BytecodeCreator creator, ResultHandle tccl,
             ParameterizedType parameterizedType) {
-        return getParameterizedType(creator, tccl, parameterizedType, null);
+        AssignableResultHandle result = creator.createVariable(Object.class);
+        getParameterizedType(result, creator, tccl, parameterizedType, null);
+        return result;
     }
 
     private static ResultHandle doLoadClass(BytecodeCreator creator, String className, ResultHandle tccl) {
@@ -546,4 +576,26 @@ static boolean containsTypeVariable(Type type) {
         return false;
     }
 
+    interface TypeCache {
+
+        void initialize(MethodCreator method);
+
+        /**
+         *
+         * @param type
+         * @param bytecode
+         * @return the cached value or {@code null}
+         */
+        ResultHandle get(Type type, BytecodeCreator bytecode);
+
+        /**
+         *
+         * @param type
+         * @param value
+         * @param bytecode
+         */
+        void put(Type type, ResultHandle value, BytecodeCreator bytecode);
+
+    }
+
 }
diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ComponentsProvider.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ComponentsProvider.java
index af2f893e657..6ef91d6baa2 100644
--- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ComponentsProvider.java
+++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/ComponentsProvider.java
@@ -1,10 +1,18 @@
 package io.quarkus.arc;
 
+import org.jboss.logging.Logger;
+
 /**
  * Service provider interface used to colllect the runtime components.
  */
 public interface ComponentsProvider {
 
+    static Logger LOG = Logger.getLogger(ComponentsProvider.class);
+
     Components getComponents();
 
+    static void unableToLoadRemovedBeanType(String type, Throwable problem) {
+        LOG.warnf("Unable to load removed bean type [%s]: %s", type, problem.toString());
+    }
+
 }
\\ No newline at end of file