Repository: quarkusio/quarkus
Issue: Unexpected beans added to the index and affecting restarting the application

### Describe the bug

I did not manage to come up with a reproducer using a regular Quarkus application. But the issue happens if you try out this branch https://github.com/pedroigor/keycloak/tree/tmp-reactive.

That branch is about switching from Resteasy Classic to Reactive in Keycloak. The issue does not happen if using Resteasy Classic and I'm not sure what is the relation, if any.

Basically, when reloading the application in dev mode or when running tests using the `QuarkusMainTestExtension`, reloading the application fails with this error:

```
org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [io.quarkus.test.junit.main.LaunchResult arg0] in method [void org.keycloak.it.cli.StartCommandTest.testHttpEnabled(io.quarkus.test.junit.main.LaunchResult)]: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
    [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: Found 8 deployment problems: 
[1] Ambiguous dependencies for type javax.transaction.TransactionManager and qualifiers [@Default]
    - java member: io.quarkus.agroal.runtime.DataSources():transactionManager
    - declared on CLASS bean [types=[io.quarkus.agroal.runtime.DataSources, java.lang.Object], qualifiers=[@Default, @Any], target=io.quarkus.agroal.runtime.DataSources]
    - available beans:
        - CLASS bean [types=[java.io.Serializable, javax.transaction.TransactionManager, com.arjuna.ats.jta.cdi.NarayanaTransactionManager, com.arjuna.ats.jta.cdi.DelegatingTransactionManager, java.lang.Object], qualifiers=[@Default, @Any], target=com.arjuna.ats.jta.cdi.NarayanaTransactionManager]
        - CLASS bean [types=[javax.transaction.TransactionManager, java.io.Serializable, io.quarkus.narayana.jta.runtime.CDIDelegatingTransactionManager, java.lang.Object], qualifiers=[@Default, @Any], target=io.quarkus.narayana.jta.runtime.CDIDelegatingTransactionManager]
```

The first start of the application works fine and only `CDIDelegatingTransactionManager` is available to resolve `TransactionManager` bean types. However, reloading the application causes the 
`com.arjuna.ats.jta.cdi.NarayanaTransactionManager` to also be recognized as a potential resolver hence failing with that error.

If we remove the `com.arjuna.ats.jta.cdi.NarayanaTransactionManager` at build time from our extension, the issue does not happen:

```
buildTimeConditionBuildItemBuildProducer.produce(new BuildTimeConditionBuildItem(index.getIndex().getClassByName(DotName.createSimple("com.arjuna.ats.jta.cdi.NarayanaTransactionManager")), false));`
```

### Expected behavior

Being able to reload the application without introducing beans that otherwise should be excluded.

### Actual behavior

Failing to reload the application as per the description.

### How to Reproduce?

* Checkout this branch https://github.com/pedroigor/keycloak/tree/tmp-reactive-bean-issue
* mvn -Pdistribution -DskipTests clean install
* cd quarkus/server
* mvn quarkus:dev -Dquarkus.args=start-dev
* After starting Keycloak in dev mode, force a restart (type `s`)

### Output of `uname -a` or `ver`

Linux fedora 6.0.9-200.fc36.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Nov 16 17:50:45 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

### Output of `java -version`

openjdk version "18.0.2.1" 2022-08-18 OpenJDK Runtime Environment (build 18.0.2.1+1-1) OpenJDK 64-Bit Server VM (build 18.0.2.1+1-1, mixed mode, sharing)

### GraalVM version (if different from Java)

_No response_

### Quarkus version or git rev

2.14.1.Final

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

_No response_

### Additional information

_No response_

Changed files:
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanDeployment.java
extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java
extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java
independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java
independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoTypesTest.java
extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveIndexBuildItem.java
extensions/spring-scheduled/deployment/src/test/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessorTest.java
independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoQualifiersTest.java
extensions/spring-di/deployment/src/test/java/io/quarkus/spring/di/deployment/SpringDIProcessorTest.java
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java
independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/ArcTestContainer.java
independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanArchives.java
independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoInjectionsTest.java

diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java
index 00fe8ebcf53..f2fb782c542 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ArcProcessor.java
@@ -277,7 +277,8 @@ public void transform(TransformationContext transformationContext) {
             }
         });
 
-        builder.setBeanArchiveIndex(index);
+        builder.setComputingBeanArchiveIndex(index);
+        builder.setImmutableBeanArchiveIndex(beanArchiveIndex.getImmutableIndex());
         builder.setApplicationIndex(combinedIndex.getIndex());
         List<BeanDefiningAnnotation> beanDefiningAnnotations = additionalBeanDefiningAnnotations.stream()
                 .map((s) -> new BeanDefiningAnnotation(s.getName(), s.getDefaultScope())).collect(Collectors.toList());
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveIndexBuildItem.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveIndexBuildItem.java
index fbb2813c638..0c0550f7d7e 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveIndexBuildItem.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveIndexBuildItem.java
@@ -14,26 +14,42 @@
  * Compared to {@link io.quarkus.deployment.builditem.CombinedIndexBuildItem} this index can contain additional classes
  * that were indexed while bean discovery was in progress.
  *
- * It also holds information about all programmatically registered beans and all generated bean classes.
- *
  * @see GeneratedBeanBuildItem
- * @see AdditionalBeanBuildItem
  * @see io.quarkus.deployment.builditem.CombinedIndexBuildItem
  */
 public final class BeanArchiveIndexBuildItem extends SimpleBuildItem {
 
     private final IndexView index;
+    private final IndexView immutableIndex;
     private final Set<DotName> generatedClassNames;
 
-    public BeanArchiveIndexBuildItem(IndexView index, Set<DotName> generatedClassNames) {
+    public BeanArchiveIndexBuildItem(IndexView index, IndexView immutableIndex, Set<DotName> generatedClassNames) {
         this.index = index;
+        this.immutableIndex = immutableIndex;
         this.generatedClassNames = generatedClassNames;
     }
 
+    /**
+     * This index is built on top of the immutable index.
+     *
+     * @return the computing index that can also index classes on demand
+     */
     public IndexView getIndex() {
         return index;
     }
 
+    /**
+     *
+     * @return an immutable index that represents the bean archive
+     */
+    public IndexView getImmutableIndex() {
+        return immutableIndex;
+    }
+
+    /**
+     *
+     * @return the set of classes generated via {@link GeneratedBeanBuildItem}
+     */
     public Set<DotName> getGeneratedClassNames() {
         return generatedClassNames;
     }
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java
index 29283e4df95..cb75954e4b3 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/BeanArchiveProcessor.java
@@ -84,12 +84,12 @@ public BeanArchiveIndexBuildItem build(ArcConfig config, ApplicationArchivesBuil
             additionalClasses.put(knownMissingClass, Optional.empty());
         }
 
-        // Finally, index ArC/CDI API built-in classes
-        return new BeanArchiveIndexBuildItem(
-                BeanArchives.buildBeanArchiveIndex(Thread.currentThread().getContextClassLoader(), additionalClasses,
-                        applicationIndex,
-                        additionalBeanIndexer.complete()),
-                generatedClassNames);
+        IndexView immutableBeanArchiveIndex = BeanArchives.buildImmutableBeanArchiveIndex(applicationIndex,
+                additionalBeanIndexer.complete());
+        IndexView computingBeanArchiveIndex = BeanArchives.buildComputingBeanArchiveIndex(
+                Thread.currentThread().getContextClassLoader(),
+                additionalClasses, immutableBeanArchiveIndex);
+        return new BeanArchiveIndexBuildItem(computingBeanArchiveIndex, immutableBeanArchiveIndex, generatedClassNames);
     }
 
     private IndexView buildApplicationIndex(ArcConfig config, ApplicationArchivesBuildItem applicationArchivesBuildItem,
diff --git a/extensions/spring-di/deployment/src/test/java/io/quarkus/spring/di/deployment/SpringDIProcessorTest.java b/extensions/spring-di/deployment/src/test/java/io/quarkus/spring/di/deployment/SpringDIProcessorTest.java
index 5791891b3fc..41e6975855d 100644
--- a/extensions/spring-di/deployment/src/test/java/io/quarkus/spring/di/deployment/SpringDIProcessorTest.java
+++ b/extensions/spring-di/deployment/src/test/java/io/quarkus/spring/di/deployment/SpringDIProcessorTest.java
@@ -205,7 +205,8 @@ public void getAnnotationsToAddBeanMethodWithScope() {
     private IndexView getIndex(final Class<?>... classes) {
         try {
             Index index = Index.of(classes);
-            return BeanArchives.buildBeanArchiveIndex(getClass().getClassLoader(), new ConcurrentHashMap<>(), index);
+            return BeanArchives.buildComputingBeanArchiveIndex(getClass().getClassLoader(), new ConcurrentHashMap<>(),
+                    BeanArchives.buildImmutableBeanArchiveIndex(index));
         } catch (IOException e) {
             throw new IllegalStateException("Failed to index classes", e);
         }
diff --git a/extensions/spring-scheduled/deployment/src/test/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessorTest.java b/extensions/spring-scheduled/deployment/src/test/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessorTest.java
index 3abb0f2f333..45db58171f5 100644
--- a/extensions/spring-scheduled/deployment/src/test/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessorTest.java
+++ b/extensions/spring-scheduled/deployment/src/test/java/io/quarkus/spring/scheduled/deployment/SpringScheduledProcessorTest.java
@@ -115,7 +115,8 @@ public void testBuildDelayParamFromInvalidFormat() {
     private IndexView getIndex(final Class<?>... classes) {
         try {
             Index index = Index.of(classes);
-            return BeanArchives.buildBeanArchiveIndex(getClass().getClassLoader(), new ConcurrentHashMap<>(), index);
+            return BeanArchives.buildComputingBeanArchiveIndex(getClass().getClassLoader(), new ConcurrentHashMap<>(),
+                    BeanArchives.buildImmutableBeanArchiveIndex(index));
         } catch (IOException e) {
             throw new IllegalStateException("Failed to index classes", e);
         }
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java
index 88e8e83a893..78c2a429fec 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/AnnotationLiteralProcessor.java
@@ -46,7 +46,7 @@ public class AnnotationLiteralProcessor {
                 generateAnnotationLiteralClassName(key.annotationName()),
                 applicationClassPredicate.test(key.annotationName()),
                 key.annotationClass));
-        this.beanArchiveIndex = beanArchiveIndex;
+        this.beanArchiveIndex = Objects.requireNonNull(beanArchiveIndex);
     }
 
     boolean hasLiteralsToGenerate() {
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanArchives.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanArchives.java
index bd14d9e679f..4a6dd5c8854 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanArchives.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanArchives.java
@@ -52,14 +52,23 @@ public final class BeanArchives {
     /**
      *
      * @param applicationIndexes
-     * @return the final bean archive index
+     * @return the immutable bean archive index
      */
-    public static IndexView buildBeanArchiveIndex(ClassLoader deploymentClassLoader,
-            Map<DotName, Optional<ClassInfo>> additionalClasses, IndexView... applicationIndexes) {
+    public static IndexView buildImmutableBeanArchiveIndex(IndexView... applicationIndexes) {
         List<IndexView> indexes = new ArrayList<>();
         Collections.addAll(indexes, applicationIndexes);
         indexes.add(buildAdditionalIndex());
-        return new IndexWrapper(CompositeIndex.create(indexes), deploymentClassLoader, additionalClasses);
+        return CompositeIndex.create(indexes);
+    }
+
+    /**
+     *
+     * @param wrappedIndexes
+     * @return the computing bean archive index
+     */
+    public static IndexView buildComputingBeanArchiveIndex(ClassLoader deploymentClassLoader,
+            Map<DotName, Optional<ClassInfo>> additionalClasses, IndexView immutableIndex) {
+        return new IndexWrapper(immutableIndex, deploymentClassLoader, additionalClasses);
     }
 
     private static IndexView buildAdditionalIndex() {
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 dfcca8ff7eb..4997affe0f4 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
@@ -14,6 +14,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -55,8 +56,8 @@ public class BeanDeployment {
 
     private final BuildContextImpl buildContext;
 
-    private final IndexView beanArchiveIndex;
-
+    private final IndexView beanArchiveComputingIndex;
+    private final IndexView beanArchiveImmutableIndex;
     private final IndexView applicationIndex;
 
     private final Map<DotName, ClassInfo> qualifiers;
@@ -124,7 +125,8 @@ public class BeanDeployment {
         }
         this.beanDefiningAnnotations = beanDefiningAnnotations;
         this.resourceAnnotations = new HashSet<>(builder.resourceAnnotations);
-        this.beanArchiveIndex = builder.beanArchiveIndex;
+        this.beanArchiveComputingIndex = builder.beanArchiveComputingIndex;
+        this.beanArchiveImmutableIndex = Objects.requireNonNull(builder.beanArchiveImmutableIndex);
         this.applicationIndex = builder.applicationIndex;
         this.annotationStore = new AnnotationStore(initAndSort(builder.annotationTransformers, buildContext), buildContext);
         if (buildContext != null) {
@@ -141,11 +143,11 @@ public class BeanDeployment {
         this.excludeTypes = builder.excludeTypes != null ? new ArrayList<>(builder.excludeTypes) : Collections.emptyList();
 
         qualifierNonbindingMembers = new HashMap<>();
-        qualifiers = findQualifiers(this.beanArchiveIndex);
+        qualifiers = findQualifiers();
         for (QualifierRegistrar registrar : builder.qualifierRegistrars) {
             for (Map.Entry<DotName, Set<String>> entry : registrar.getAdditionalQualifiers().entrySet()) {
                 DotName dotName = entry.getKey();
-                ClassInfo classInfo = getClassByName(this.beanArchiveIndex, dotName);
+                ClassInfo classInfo = getClassByName(getBeanArchiveIndex(), dotName);
                 if (classInfo != null) {
                     Set<String> nonbindingMembers = entry.getValue();
                     if (nonbindingMembers == null) {
@@ -156,15 +158,15 @@ public class BeanDeployment {
                 }
             }
         }
-        repeatingQualifierAnnotations = findContainerAnnotations(qualifiers, this.beanArchiveIndex);
+        repeatingQualifierAnnotations = findContainerAnnotations(qualifiers);
         buildContextPut(Key.QUALIFIERS.asString(), Collections.unmodifiableMap(qualifiers));
 
         interceptorNonbindingMembers = new HashMap<>();
-        interceptorBindings = findInterceptorBindings(this.beanArchiveIndex);
+        interceptorBindings = findInterceptorBindings();
         for (InterceptorBindingRegistrar registrar : builder.interceptorBindingRegistrars) {
             for (InterceptorBindingRegistrar.InterceptorBinding binding : registrar.getAdditionalBindings()) {
                 DotName dotName = binding.getName();
-                ClassInfo annotationClass = getClassByName(this.beanArchiveIndex, dotName);
+                ClassInfo annotationClass = getClassByName(getBeanArchiveIndex(), dotName);
                 if (annotationClass != null) {
                     Set<String> nonbinding = new HashSet<>();
                     for (MethodInfo method : annotationClass.methods()) {
@@ -177,7 +179,7 @@ public class BeanDeployment {
                 interceptorBindings.put(dotName, annotationClass);
             }
         }
-        repeatingInterceptorBindingAnnotations = findContainerAnnotations(interceptorBindings, this.beanArchiveIndex);
+        repeatingInterceptorBindingAnnotations = findContainerAnnotations(interceptorBindings);
         buildContextPut(Key.INTERCEPTOR_BINDINGS.asString(), Collections.unmodifiableMap(interceptorBindings));
 
         Set<DotName> additionalStereotypes = new HashSet<>();
@@ -185,12 +187,11 @@ public class BeanDeployment {
             additionalStereotypes.addAll(stereotypeRegistrar.getAdditionalStereotypes());
         }
 
-        this.stereotypes = findStereotypes(this.beanArchiveIndex, interceptorBindings, customContexts, additionalStereotypes,
+        this.stereotypes = findStereotypes(interceptorBindings, customContexts, additionalStereotypes,
                 annotationStore);
         buildContextPut(Key.STEREOTYPES.asString(), Collections.unmodifiableMap(stereotypes));
 
         this.transitiveInterceptorBindings = findTransitiveInterceptorBindings(interceptorBindings.keySet(),
-                this.beanArchiveIndex,
                 new HashMap<>(), interceptorBindings, annotationStore);
 
         this.injectionPoints = new CopyOnWriteArrayList<>();
@@ -199,7 +200,7 @@ public class BeanDeployment {
         this.beans = new CopyOnWriteArrayList<>();
         this.observers = new CopyOnWriteArrayList<>();
 
-        this.assignabilityCheck = new AssignabilityCheck(beanArchiveIndex, applicationIndex);
+        this.assignabilityCheck = new AssignabilityCheck(getBeanArchiveIndex(), applicationIndex);
         this.beanResolver = new BeanResolverImpl(this);
         this.delegateInjectionPointResolver = new DelegateInjectionPointResolverImpl(this);
         this.interceptorResolver = new InterceptorResolver(this);
@@ -517,12 +518,17 @@ public Collection<StereotypeInfo> getStereotypes() {
     }
 
     /**
-     * This index was used to discover components (beans, interceptors, qualifiers, etc.) and during type-safe resolution.
+     * Returns the index that was used during discovery and type-safe resolution.
+     * <p>
+     * In general, the returned index is usually "computing" which means that it attempts to compute the information for the
+     * classes that were not part of the initial bean archive index. I.e. the returned index corresponds to
+     * {@link BeanProcessor.Builder#setComputingBeanArchiveIndex(IndexView)}. However, if the computing index was not set then
+     * the index set by {@link BeanProcessor.Builder#setImmutableBeanArchiveIndex(IndexView)} is used instead.
      *
      * @return the bean archive index
      */
     public IndexView getBeanArchiveIndex() {
-        return beanArchiveIndex;
+        return beanArchiveComputingIndex != null ? beanArchiveComputingIndex : beanArchiveImmutableIndex;
     }
 
     /**
@@ -670,9 +676,9 @@ private void buildContextPut(String key, Object value) {
         }
     }
 
-    private Map<DotName, ClassInfo> findQualifiers(IndexView index) {
+    private Map<DotName, ClassInfo> findQualifiers() {
         Map<DotName, ClassInfo> qualifiers = new HashMap<>();
-        for (AnnotationInstance qualifier : index.getAnnotations(DotNames.QUALIFIER)) {
+        for (AnnotationInstance qualifier : beanArchiveImmutableIndex.getAnnotations(DotNames.QUALIFIER)) {
             ClassInfo qualifierClass = qualifier.target().asClass();
             if (isExcluded(qualifierClass)) {
                 continue;
@@ -682,23 +688,23 @@ private Map<DotName, ClassInfo> findQualifiers(IndexView index) {
         return qualifiers;
     }
 
-    private Map<DotName, ClassInfo> findContainerAnnotations(Map<DotName, ClassInfo> annotations, IndexView index) {
+    private Map<DotName, ClassInfo> findContainerAnnotations(Map<DotName, ClassInfo> annotations) {
         Map<DotName, ClassInfo> containerAnnotations = new HashMap<>();
         for (ClassInfo annotation : annotations.values()) {
             AnnotationInstance repeatableMetaAnnotation = annotation.declaredAnnotation(DotNames.REPEATABLE);
             if (repeatableMetaAnnotation != null) {
                 DotName containerAnnotationName = repeatableMetaAnnotation.value().asClass().name();
-                ClassInfo containerClass = getClassByName(index, containerAnnotationName);
+                ClassInfo containerClass = getClassByName(getBeanArchiveIndex(), containerAnnotationName);
                 containerAnnotations.put(containerAnnotationName, containerClass);
             }
         }
         return containerAnnotations;
     }
 
-    private Map<DotName, ClassInfo> findInterceptorBindings(IndexView index) {
+    private Map<DotName, ClassInfo> findInterceptorBindings() {
         Map<DotName, ClassInfo> bindings = new HashMap<>();
         // Note: doesn't use AnnotationStore, this will operate on classes without applying annotation transformers
-        for (AnnotationInstance binding : index.getAnnotations(DotNames.INTERCEPTOR_BINDING)) {
+        for (AnnotationInstance binding : beanArchiveImmutableIndex.getAnnotations(DotNames.INTERCEPTOR_BINDING)) {
             ClassInfo bindingClass = binding.target().asClass();
             if (isExcluded(bindingClass)) {
                 continue;
@@ -709,7 +715,6 @@ private Map<DotName, ClassInfo> findInterceptorBindings(IndexView index) {
     }
 
     private static Map<DotName, Set<AnnotationInstance>> findTransitiveInterceptorBindings(Collection<DotName> initialBindings,
-            IndexView index,
             Map<DotName, Set<AnnotationInstance>> result, Map<DotName, ClassInfo> interceptorBindings,
             AnnotationStore annotationStore) {
         // for all known interceptor bindings
@@ -748,20 +753,20 @@ private static Set<AnnotationInstance> recursiveBuild(DotName name,
         return result;
     }
 
-    private Map<DotName, StereotypeInfo> findStereotypes(IndexView index, Map<DotName, ClassInfo> interceptorBindings,
+    private Map<DotName, StereotypeInfo> findStereotypes(Map<DotName, ClassInfo> interceptorBindings,
             Map<ScopeInfo, Function<MethodCreator, ResultHandle>> customContexts,
             Set<DotName> additionalStereotypes, AnnotationStore annotationStore) {
 
         Map<DotName, StereotypeInfo> stereotypes = new HashMap<>();
 
         Set<DotName> stereotypeNames = new HashSet<>();
-        for (AnnotationInstance annotation : index.getAnnotations(DotNames.STEREOTYPE)) {
+        for (AnnotationInstance annotation : beanArchiveImmutableIndex.getAnnotations(DotNames.STEREOTYPE)) {
             stereotypeNames.add(annotation.target().asClass().name());
         }
         stereotypeNames.addAll(additionalStereotypes);
 
         for (DotName stereotypeName : stereotypeNames) {
-            ClassInfo stereotypeClass = getClassByName(index, stereotypeName);
+            ClassInfo stereotypeClass = getClassByName(getBeanArchiveIndex(), stereotypeName);
             if (stereotypeClass != null && !isExcluded(stereotypeClass)) {
 
                 boolean isAlternative = false;
@@ -852,7 +857,8 @@ private List<BeanInfo> findBeans(Collection<DotName> beanDefiningAnnotations, Li
                 .map(StereotypeInfo::getName)
                 .collect(Collectors.toSet());
 
-        for (ClassInfo beanClass : beanArchiveIndex.getKnownClasses()) {
+        // If needed use the specialized immutable index to discover beans
+        for (ClassInfo beanClass : beanArchiveImmutableIndex.getKnownClasses()) {
 
             if (Modifier.isInterface(beanClass.flags()) || Modifier.isAbstract(beanClass.flags())
                     || beanClass.isAnnotation() || beanClass.isEnum()) {
@@ -987,7 +993,7 @@ private List<BeanInfo> findBeans(Collection<DotName> beanDefiningAnnotations, Li
                 }
                 DotName superType = aClass.superName();
                 aClass = superType != null && !superType.equals(DotNames.OBJECT)
-                        ? getClassByName(beanArchiveIndex, superType)
+                        ? getClassByName(getBeanArchiveIndex(), superType)
                         : null;
             }
             for (FieldInfo field : beanClass.fields()) {
@@ -1233,7 +1239,7 @@ static void processErrors(List<Throwable> errors) {
 
     private List<InterceptorInfo> findInterceptors(List<InjectionPointInfo> injectionPoints) {
         Map<DotName, ClassInfo> interceptorClasses = new HashMap<>();
-        for (AnnotationInstance annotation : beanArchiveIndex.getAnnotations(DotNames.INTERCEPTOR)) {
+        for (AnnotationInstance annotation : beanArchiveImmutableIndex.getAnnotations(DotNames.INTERCEPTOR)) {
             if (Kind.CLASS.equals(annotation.target().kind())) {
                 interceptorClasses.put(annotation.target().asClass().name(), annotation.target().asClass());
             }
@@ -1260,7 +1266,7 @@ private List<InterceptorInfo> findInterceptors(List<InjectionPointInfo> injectio
 
     private List<DecoratorInfo> findDecorators(List<InjectionPointInfo> injectionPoints) {
         Map<DotName, ClassInfo> decoratorClasses = new HashMap<>();
-        for (AnnotationInstance annotation : beanArchiveIndex.getAnnotations(DotNames.DECORATOR)) {
+        for (AnnotationInstance annotation : beanArchiveImmutableIndex.getAnnotations(DotNames.DECORATOR)) {
             if (Kind.CLASS.equals(annotation.target().kind())) {
                 decoratorClasses.put(annotation.target().asClass().name(), annotation.target().asClass());
             }
diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java
index b869031c546..4427cfe4bea 100644
--- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java
+++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/BeanProcessor.java
@@ -91,7 +91,10 @@ private BeanProcessor(Builder builder) {
         this.applicationClassPredicate = builder.applicationClassPredicate;
         this.name = builder.name;
         this.output = builder.output;
-        this.annotationLiterals = new AnnotationLiteralProcessor(builder.beanArchiveIndex, applicationClassPredicate);
+        this.annotationLiterals = new AnnotationLiteralProcessor(
+                builder.beanArchiveComputingIndex != null ? builder.beanArchiveComputingIndex
+                        : builder.beanArchiveImmutableIndex,
+                applicationClassPredicate);
         this.generateSources = builder.generateSources;
         this.allowMocking = builder.allowMocking;
         this.transformUnproxyableClasses = builder.transformUnproxyableClasses;
@@ -99,7 +102,9 @@ private BeanProcessor(Builder builder) {
 
         // Initialize all build processors
         buildContext = new BuildContextImpl();
-        buildContext.putInternal(Key.INDEX.asString(), builder.beanArchiveIndex);
+        buildContext.putInternal(Key.INDEX.asString(),
+                builder.beanArchiveComputingIndex != null ? builder.beanArchiveComputingIndex
+                        : builder.beanArchiveImmutableIndex);
 
         this.beanRegistrars = initAndSort(builder.beanRegistrars, buildContext);
         this.observerRegistrars = initAndSort(builder.observerRegistrars, buildContext);
@@ -440,7 +445,8 @@ public Predicate<DotName> getInjectionPointAnnotationsPredicate() {
     public static class Builder {
 
         String name;
-        IndexView beanArchiveIndex;
+        IndexView beanArchiveComputingIndex;
+        IndexView beanArchiveImmutableIndex;
         IndexView applicationIndex;
         Collection<BeanDefiningAnnotation> additionalBeanDefiningAnnotations;
         ResourceOutput output;
@@ -510,14 +516,33 @@ public Builder setName(String name) {
         }
 
         /**
-         * Set the bean archive index. This index is mandatory and is used to discover components (beans, interceptors,
-         * qualifiers, etc.) and during type-safe resolution.
+         * Set the computing bean archive index. This index is optional and can be used for example during type-safe resolution.
+         * If it's not set then the immutable index is used instead.
+         * <p>
+         * The computing index must be built on top of the immutable index and compute only the classes that are not part of the
+         * immutable index.
+         * <p>
+         * This index is never used to discover components (beans, observers, etc.).
+         *
+         * @param index
+         * @return self
+         * @see Builder#setImmutableBeanArchiveIndex(IndexView)
+         */
+        public Builder setComputingBeanArchiveIndex(IndexView index) {
+            this.beanArchiveComputingIndex = index;
+            return this;
+        }
+
+        /**
+         * Set the immutable bean archive index. This index is mandatory and is used to discover components (beans, observers,
+         * etc.).
          *
-         * @param beanArchiveIndex
+         * @param index
          * @return self
+         * @see Builder#setComputingBeanArchiveIndex(IndexView)
          */
-        public Builder setBeanArchiveIndex(IndexView beanArchiveIndex) {
-            this.beanArchiveIndex = beanArchiveIndex;
+        public Builder setImmutableBeanArchiveIndex(IndexView index) {
+            this.beanArchiveImmutableIndex = index;
             return this;
         }
 
@@ -526,11 +551,11 @@ public Builder setBeanArchiveIndex(IndexView beanArchiveIndex) {
          * <p>
          * Some types may not be part of the bean archive index but are still needed during type-safe resolution.
          *
-         * @param applicationIndex
+         * @param index
          * @return self
          */
-        public Builder setApplicationIndex(IndexView applicationIndex) {
-            this.applicationIndex = applicationIndex;
+        public Builder setApplicationIndex(IndexView index) {
+            this.applicationIndex = index;
             return this;
         }
 
diff --git a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoInjectionsTest.java b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoInjectionsTest.java
index 981ae74c5bd..ff22bbd5688 100644
--- a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoInjectionsTest.java
+++ b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoInjectionsTest.java
@@ -42,7 +42,7 @@ public void testInjections() throws IOException {
         Type listStringType = ParameterizedType.create(name(List.class),
                 new Type[] { Type.create(name(String.class), Kind.CLASS) }, null);
 
-        BeanDeployment deployment = BeanProcessor.builder().setBeanArchiveIndex(index).build().getBeanDeployment();
+        BeanDeployment deployment = BeanProcessor.builder().setImmutableBeanArchiveIndex(index).build().getBeanDeployment();
         deployment.registerCustomContexts(Collections.emptyList());
         deployment.registerBeans(Collections.emptyList());
         BeanInfo barBean = deployment.getBeans().stream().filter(b -> b.getTarget().get().equals(barClass)).findFirst().get();
diff --git a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoQualifiersTest.java b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoQualifiersTest.java
index 6e5203478b4..3c95a2c557f 100644
--- a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoQualifiersTest.java
+++ b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoQualifiersTest.java
@@ -37,7 +37,7 @@ public void testQualifiers() throws IOException {
         ClassInfo fooClass = index.getClassByName(fooName);
 
         BeanInfo bean = Beans.createClassBean(fooClass,
-                BeanProcessor.builder().setBeanArchiveIndex(index).build().getBeanDeployment(),
+                BeanProcessor.builder().setImmutableBeanArchiveIndex(index).build().getBeanDeployment(),
                 null);
 
         AnnotationInstance requiredFooQualifier = index.getAnnotations(fooQualifierName).stream()
diff --git a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoTypesTest.java b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoTypesTest.java
index 75dd27ee2e3..bc53674cd78 100644
--- a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoTypesTest.java
+++ b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/BeanInfoTypesTest.java
@@ -37,7 +37,7 @@ public void testResolver() throws IOException {
                 Collection.class, List.class,
                 Iterable.class, Object.class, String.class);
 
-        BeanDeployment deployment = BeanProcessor.builder().setBeanArchiveIndex(index).build().getBeanDeployment();
+        BeanDeployment deployment = BeanProcessor.builder().setImmutableBeanArchiveIndex(index).build().getBeanDeployment();
         DotName fooName = name(Foo.class);
 
         ClassInfo fooClass = index.getClassByName(fooName);
diff --git a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java
index b6bcc935947..fbe3e19e240 100644
--- a/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java
+++ b/independent-projects/arc/processor/src/test/java/io/quarkus/arc/processor/TypesTest.java
@@ -32,7 +32,8 @@ public void testGetTypeClosure() throws IOException {
         DotName producerName = DotName.createSimple(Producer.class.getName());
         ClassInfo fooClass = index.getClassByName(fooName);
         Map<ClassInfo, Map<String, Type>> resolvedTypeVariables = new HashMap<>();
-        BeanDeployment dummyDeployment = BeanProcessor.builder().setBeanArchiveIndex(index).build().getBeanDeployment();
+        BeanDeployment dummyDeployment = BeanProcessor.builder().setImmutableBeanArchiveIndex(index).build()
+                .getBeanDeployment();
 
         // Baz, Foo<String>, Object
         Set<Type> bazTypes = Types.getTypeClosure(index.getClassByName(bazName), null,
diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/ArcTestContainer.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/ArcTestContainer.java
index 6d428b83335..fda3d072e71 100644
--- a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/ArcTestContainer.java
+++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/ArcTestContainer.java
@@ -20,6 +20,7 @@
 
 import org.jboss.jandex.DotName;
 import org.jboss.jandex.Index;
+import org.jboss.jandex.IndexView;
 import org.jboss.jandex.Indexer;
 import org.junit.jupiter.api.extension.AfterEachCallback;
 import org.junit.jupiter.api.extension.BeforeEachCallback;
@@ -322,14 +323,14 @@ private ClassLoader init(ExtensionContext context) {
         Arc.shutdown();
 
         // Build index
-        Index beanArchiveIndex;
+        IndexView immutableBeanArchiveIndex;
         try {
-            beanArchiveIndex = index(beanClasses);
+            immutableBeanArchiveIndex = BeanArchives.buildImmutableBeanArchiveIndex(index(beanClasses));
         } catch (IOException e) {
             throw new IllegalStateException("Failed to create index", e);
         }
 
-        Index applicationIndex;
+        IndexView applicationIndex;
         if (additionalClasses.isEmpty()) {
             applicationIndex = null;
         } else {
@@ -370,8 +371,9 @@ private ClassLoader init(ExtensionContext context) {
 
             BeanProcessor.Builder builder = BeanProcessor.builder()
                     .setName(testClass.getSimpleName())
-                    .setBeanArchiveIndex(BeanArchives.buildBeanArchiveIndex(getClass().getClassLoader(),
-                            new ConcurrentHashMap<>(), beanArchiveIndex))
+                    .setImmutableBeanArchiveIndex(immutableBeanArchiveIndex)
+                    .setComputingBeanArchiveIndex(BeanArchives.buildComputingBeanArchiveIndex(getClass().getClassLoader(),
+                            new ConcurrentHashMap<>(), immutableBeanArchiveIndex))
                     .setApplicationIndex(applicationIndex);
             if (!resourceAnnotations.isEmpty()) {
                 builder.addResourceAnnotations(resourceAnnotations.stream()